Skip to content

Commit 8aaf8f2

Browse files
committed
Merge pull request #498 from drew-gross/test-configurations
Add ability to test multiple server configurations
2 parents 78c5292 + 5378de7 commit 8aaf8f2

File tree

5 files changed

+138
-51
lines changed

5 files changed

+138
-51
lines changed

spec/helper.js

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,17 @@ var DatabaseAdapter = require('../src/DatabaseAdapter');
77
var express = require('express');
88
var facebook = require('../src/oauth/facebook');
99
var ParseServer = require('../src/index').ParseServer;
10+
var DatabaseAdapter = require('../src/DatabaseAdapter');
1011

1112
var databaseURI = process.env.DATABASE_URI;
1213
var cloudMain = process.env.CLOUD_CODE_MAIN || './cloud/main.js';
14+
var port = 8378;
1315

14-
// Set up an API server for testing
15-
var api = new ParseServer({
16+
// Default server configuration for tests.
17+
var defaultConfiguration = {
1618
databaseURI: databaseURI,
1719
cloud: cloudMain,
20+
serverURL: 'http://localhost:' + port + '/1',
1821
appId: 'test',
1922
javascriptKey: 'test',
2023
dotNetKey: 'windows',
@@ -29,13 +32,29 @@ var api = new ParseServer({
2932
module: "../spec/myoauth" // relative path as it's run from src
3033
}
3134
}
32-
});
35+
};
3336

37+
// Set up a default API server for testing with default configuration.
38+
var api = new ParseServer(defaultConfiguration);
3439
var app = express();
3540
app.use('/1', api);
36-
var port = 8378;
3741
var server = app.listen(port);
3842

43+
// Prevent reinitializing the server from clobbering Cloud Code
44+
delete defaultConfiguration.cloud;
45+
46+
// Allows testing specific configurations of Parse Server
47+
var setServerConfiguration = configuration => {
48+
api = new ParseServer(configuration);
49+
app = express();
50+
app.use('/1', api);
51+
cache.clearCache();
52+
server.close();
53+
server = app.listen(port);
54+
}
55+
56+
var restoreServerConfiguration = () => setServerConfiguration(defaultConfiguration);
57+
3958
// Set up a Parse client to talk to our test API server
4059
var Parse = require('parse/node');
4160
Parse.serverURL = 'http://localhost:' + port + '/1';
@@ -51,9 +70,11 @@ beforeEach(function(done) {
5170
});
5271

5372
afterEach(function(done) {
73+
restoreServerConfiguration();
5474
Parse.User.logOut().then(() => {
5575
return clearData();
5676
}).then(() => {
77+
DatabaseAdapter.clearDatabaseURIs();
5778
done();
5879
}, (error) => {
5980
console.log('error in clearData', error);
@@ -221,3 +242,4 @@ global.expectError = expectError;
221242
global.arrayContains = arrayContains;
222243
global.jequal = jequal;
223244
global.range = range;
245+
global.setServerConfiguration = setServerConfiguration;

spec/index.spec.js

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
var request = require('request');
2+
3+
describe('server', () => {
4+
it('requires a master key and app id', done => {
5+
expect(setServerConfiguration.bind(undefined, { masterKey: 'mykey' })).toThrow('You must provide an appId and masterKey!');
6+
expect(setServerConfiguration.bind(undefined, { appId: 'myId' })).toThrow('You must provide an appId and masterKey!');
7+
done();
8+
});
9+
10+
it('fails if database is unreachable', done => {
11+
setServerConfiguration({
12+
databaseURI: 'mongodb://fake:[email protected]:43605/drew3',
13+
serverURL: 'http://localhost:8378/1',
14+
appId: 'test',
15+
javascriptKey: 'test',
16+
dotNetKey: 'windows',
17+
clientKey: 'client',
18+
restAPIKey: 'rest',
19+
masterKey: 'test',
20+
collectionPrefix: 'test_',
21+
fileKey: 'test',
22+
});
23+
//Need to use rest api because saving via JS SDK results in fail() not getting called
24+
request.post({
25+
url: 'http://localhost:8378/1/classes/NewClass',
26+
headers: {
27+
'X-Parse-Application-Id': 'test',
28+
'X-Parse-REST-API-Key': 'rest',
29+
},
30+
body: {},
31+
json: true,
32+
}, (error, response, body) => {
33+
expect(response.statusCode).toEqual(500);
34+
expect(body.code).toEqual(1);
35+
expect(body.message).toEqual('Internal server error.');
36+
done();
37+
});
38+
});
39+
});

src/DatabaseAdapter.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,12 @@ function setAppDatabaseURI(appId, uri) {
3434
appDatabaseURIs[appId] = uri;
3535
}
3636

37+
//Used by tests
38+
function clearDatabaseURIs() {
39+
appDatabaseURIs = {};
40+
dbConnections = {};
41+
}
42+
3743
function getDatabaseConnection(appId) {
3844
if (dbConnections[appId]) {
3945
return dbConnections[appId];
@@ -52,5 +58,6 @@ module.exports = {
5258
getDatabaseConnection: getDatabaseConnection,
5359
setAdapter: setAdapter,
5460
setDatabaseURI: setDatabaseURI,
55-
setAppDatabaseURI: setAppDatabaseURI
61+
setAppDatabaseURI: setAppDatabaseURI,
62+
clearDatabaseURIs: clearDatabaseURIs,
5663
};

src/cache.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,13 @@ function clearUser(sessionToken) {
2525
delete users[sessionToken];
2626
}
2727

28+
//So far used only in tests
29+
function clearCache() {
30+
apps = {};
31+
stats = {};
32+
users = {};
33+
}
34+
2835
module.exports = {
2936
apps: apps,
3037
stats: stats,
@@ -33,5 +40,6 @@ module.exports = {
3340
updateStat: updateStat,
3441
clearUser: clearUser,
3542
getUser: getUser,
36-
setUser: setUser
43+
setUser: setUser,
44+
clearCache: clearCache,
3745
};

src/index.js

Lines changed: 56 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,21 @@ var batch = require('./batch'),
1111
PromiseRouter = require('./PromiseRouter'),
1212
httpRequest = require('./httpRequest');
1313

14-
import { GridStoreAdapter } from './Adapters/Files/GridStoreAdapter';
15-
import { S3Adapter } from './Adapters/Files/S3Adapter';
16-
import { FilesController } from './Controllers/FilesController';
14+
import { GridStoreAdapter } from './Adapters/Files/GridStoreAdapter';
15+
import { S3Adapter } from './Adapters/Files/S3Adapter';
16+
import { FilesController } from './Controllers/FilesController';
1717

18-
import ParsePushAdapter from './Adapters/Push/ParsePushAdapter';
19-
import { PushController } from './Controllers/PushController';
18+
import ParsePushAdapter from './Adapters/Push/ParsePushAdapter';
19+
import { PushController } from './Controllers/PushController';
2020

21-
import { ClassesRouter } from './Routers/ClassesRouter';
21+
import { ClassesRouter } from './Routers/ClassesRouter';
2222
import { InstallationsRouter } from './Routers/InstallationsRouter';
23-
import { UsersRouter } from './Routers/UsersRouter';
24-
import { SessionsRouter } from './Routers/SessionsRouter';
25-
import { RolesRouter } from './Routers/RolesRouter';
23+
import { UsersRouter } from './Routers/UsersRouter';
24+
import { SessionsRouter } from './Routers/SessionsRouter';
25+
import { RolesRouter } from './Routers/RolesRouter';
2626

27-
import { FileLoggerAdapter } from './Adapters/Logger/FileLoggerAdapter';
28-
import { LoggerController } from './Controllers/LoggerController';
27+
import { FileLoggerAdapter } from './Adapters/Logger/FileLoggerAdapter';
28+
import { LoggerController } from './Controllers/LoggerController';
2929

3030
// Mutate the Parse object to add the Cloud Code handlers
3131
addParseCloud();
@@ -54,69 +54,81 @@ addParseCloud();
5454
// "javascriptKey": optional key from Parse dashboard
5555
// "push": optional key from configure push
5656

57-
function ParseServer(args) {
58-
if (!args.appId || !args.masterKey) {
57+
function ParseServer({
58+
appId,
59+
masterKey,
60+
databaseAdapter,
61+
filesAdapter = new GridStoreAdapter(),
62+
push,
63+
loggerAdapter = new FileLoggerAdapter(),
64+
databaseURI,
65+
cloud,
66+
collectionPrefix = '',
67+
clientKey = '',
68+
javascriptKey = '',
69+
dotNetKey = '',
70+
restAPIKey = '',
71+
fileKey = 'invalid-file-key',
72+
facebookAppIds = [],
73+
enableAnonymousUsers = true,
74+
oauth = {},
75+
serverURL = '',
76+
}) {
77+
if (!appId || !masterKey) {
5978
throw 'You must provide an appId and masterKey!';
6079
}
6180

62-
if (args.databaseAdapter) {
63-
DatabaseAdapter.setAdapter(args.databaseAdapter);
81+
if (databaseAdapter) {
82+
DatabaseAdapter.setAdapter(databaseAdapter);
6483
}
6584

66-
// Make files adapter
67-
let filesAdapter = args.filesAdapter || new GridStoreAdapter();
68-
6985
// Make push adapter
70-
let pushConfig = args.push;
86+
let pushConfig = push;
7187
let pushAdapter;
7288
if (pushConfig && pushConfig.adapter) {
7389
pushAdapter = pushConfig.adapter;
7490
} else if (pushConfig) {
7591
pushAdapter = new ParsePushAdapter(pushConfig)
7692
}
7793

78-
// Make logger adapter
79-
let loggerAdapter = args.loggerAdapter || new FileLoggerAdapter();
80-
81-
if (args.databaseURI) {
82-
DatabaseAdapter.setAppDatabaseURI(args.appId, args.databaseURI);
94+
if (databaseURI) {
95+
DatabaseAdapter.setAppDatabaseURI(appId, databaseURI);
8396
}
84-
if (args.cloud) {
97+
if (cloud) {
8598
addParseCloud();
86-
if (typeof args.cloud === 'function') {
87-
args.cloud(Parse)
88-
} else if (typeof args.cloud === 'string') {
89-
require(args.cloud);
99+
if (typeof cloud === 'function') {
100+
cloud(Parse)
101+
} else if (typeof cloud === 'string') {
102+
require(cloud);
90103
} else {
91104
throw "argument 'cloud' must either be a string or a function";
92105
}
93-
94106
}
95107

96108
let filesController = new FilesController(filesAdapter);
97109

98-
cache.apps[args.appId] = {
99-
masterKey: args.masterKey,
100-
collectionPrefix: args.collectionPrefix || '',
101-
clientKey: args.clientKey || '',
102-
javascriptKey: args.javascriptKey || '',
103-
dotNetKey: args.dotNetKey || '',
104-
restAPIKey: args.restAPIKey || '',
105-
fileKey: args.fileKey || 'invalid-file-key',
106-
facebookAppIds: args.facebookAppIds || [],
110+
cache.apps[appId] = {
111+
masterKey: masterKey,
112+
collectionPrefix: collectionPrefix,
113+
clientKey: clientKey,
114+
javascriptKey: javascriptKey,
115+
dotNetKey: dotNetKey,
116+
restAPIKey: restAPIKey,
117+
fileKey: fileKey,
118+
facebookAppIds: facebookAppIds,
107119
filesController: filesController,
108-
enableAnonymousUsers: args.enableAnonymousUsers || true,
109-
oauth: args.oauth || {},
120+
enableAnonymousUsers: enableAnonymousUsers,
121+
oauth: oauth,
110122
};
111123

112124
// To maintain compatibility. TODO: Remove in v2.1
113125
if (process.env.FACEBOOK_APP_ID) {
114-
cache.apps[args.appId]['facebookAppIds'].push(process.env.FACEBOOK_APP_ID);
126+
cache.apps[appId]['facebookAppIds'].push(process.env.FACEBOOK_APP_ID);
115127
}
116128

117129
// Initialize the node client SDK automatically
118-
Parse.initialize(args.appId, args.javascriptKey || '', args.masterKey);
119-
Parse.serverURL = args.serverURL || '';
130+
Parse.initialize(appId, javascriptKey, masterKey);
131+
Parse.serverURL = serverURL;
120132

121133
// This app serves the Parse API directly.
122134
// It's the equivalent of https://api.parse.com/1 in the hosted Parse API.
@@ -127,7 +139,6 @@ function ParseServer(args) {
127139

128140
// TODO: separate this from the regular ParseServer object
129141
if (process.env.TESTING == 1) {
130-
console.log('enabling integration testing-routes');
131142
api.use('/', require('./testing-routes').router);
132143
}
133144

0 commit comments

Comments
 (0)