Skip to content

Commit 478147c

Browse files
authored
test: Prevent test timeout error by properly closing server (#2490)
1 parent 43cba58 commit 478147c

File tree

6 files changed

+71
-57
lines changed

6 files changed

+71
-57
lines changed

integration/test/ParseEventuallyQueueTest.js

+3-6
Original file line numberDiff line numberDiff line change
@@ -193,8 +193,7 @@ describe('Parse EventuallyQueue', () => {
193193
it('can saveEventually', async () => {
194194
const parseServer = await reconfigureServer();
195195
const object = new TestObject({ hash: 'saveSecret' });
196-
await parseServer.handleShutdown();
197-
await new Promise(resolve => parseServer.server.close(resolve));
196+
await shutdownServer(parseServer);
198197
await object.saveEventually();
199198

200199
const length = await Parse.EventuallyQueue.length();
@@ -225,8 +224,7 @@ describe('Parse EventuallyQueue', () => {
225224
const acl = new Parse.ACL(user);
226225
const object = new TestObject({ hash: 'saveSecret' });
227226
object.setACL(acl);
228-
await parseServer.handleShutdown();
229-
await new Promise(resolve => parseServer.server.close(resolve));
227+
await shutdownServer(parseServer);
230228
await object.saveEventually();
231229

232230
const length = await Parse.EventuallyQueue.length();
@@ -251,8 +249,7 @@ describe('Parse EventuallyQueue', () => {
251249
const parseServer = await reconfigureServer();
252250
const object = new TestObject({ hash: 'deleteSecret' });
253251
await object.save();
254-
await parseServer.handleShutdown();
255-
await new Promise(resolve => parseServer.server.close(resolve));
252+
await shutdownServer(parseServer);
256253
await object.destroyEventually();
257254
const length = await Parse.EventuallyQueue.length();
258255

integration/test/ParseServerTest.js

+21-10
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,37 @@
11
'use strict';
22

3-
const assert = require('assert');
4-
53
describe('ParseServer', () => {
64
it('can reconfigure server', async () => {
7-
const parseServer = await reconfigureServer({ serverURL: 'www.google.com' });
8-
assert.strictEqual(parseServer.config.serverURL, 'www.google.com');
9-
await parseServer.handleShutdown();
10-
await new Promise(resolve => parseServer.server.close(resolve));
11-
await reconfigureServer();
5+
let parseServer = await reconfigureServer({ serverURL: 'www.google.com' });
6+
expect(parseServer.config.serverURL).toBe('www.google.com');
7+
8+
await shutdownServer(parseServer);
9+
10+
parseServer = await reconfigureServer();
11+
expect(parseServer.config.serverURL).toBe('http://localhost:1337/parse');
1212
});
1313

1414
it('can shutdown', async () => {
15+
let close = 0;
1516
const parseServer = await reconfigureServer();
17+
parseServer.server.on('close', () => {
18+
close += 1;
19+
});
1620
const object = new TestObject({ foo: 'bar' });
17-
await parseServer.handleShutdown();
18-
await new Promise(resolve => parseServer.server.close(resolve));
21+
// Open a connection to the server
22+
const query = new Parse.Query(TestObject);
23+
await query.subscribe();
24+
expect(openConnections.size > 0).toBeTruthy();
25+
26+
await shutdownServer(parseServer);
27+
expect(close).toBe(1);
28+
expect(openConnections.size).toBe(0);
29+
1930
await expectAsync(object.save()).toBeRejectedWithError(
2031
'XMLHttpRequest failed: "Unable to connect to the Parse API"'
2132
);
2233
await reconfigureServer({});
2334
await object.save();
24-
assert(object.id);
35+
expect(object.id).toBeDefined();
2536
});
2637
});

integration/test/ParseUserTest.js

+2-3
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ const provider = {
2828
};
2929
},
3030
};
31-
Parse.User._registerAuthenticationProvider(provider);
3231

3332
const authResponse = {
3433
userID: 'test',
@@ -44,8 +43,8 @@ global.FB = {
4443
};
4544

4645
describe('Parse User', () => {
47-
afterAll(() => {
48-
Parse.Object.unregisterSubclass('CustomUser');
46+
beforeEach(() => {
47+
Parse.User._registerAuthenticationProvider(provider);
4948
});
5049

5150
it('can sign up users via static method', done => {

integration/test/clear.js

-12
This file was deleted.

integration/test/helper.js

+44-24
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ const ParseServer = require('parse-server').default;
77
const CustomAuth = require('./CustomAuth');
88
const { TestUtils } = require('parse-server');
99
const Parse = require('../../node');
10-
const fs = require('fs');
10+
const { resolvingPromise } = require('../../lib/node/promiseUtils');
11+
const fs = require('fs').promises;
1112
const path = require('path');
1213
const dns = require('dns');
1314
const MockEmailAdapterWithOptions = require('./support/MockEmailAdapterWithOptions');
@@ -21,6 +22,7 @@ const port = 1337;
2122
const mountPath = '/parse';
2223
const serverURL = 'http://localhost:1337/parse';
2324
let didChangeConfiguration = false;
25+
const distFiles = {};
2426

2527
/*
2628
To generate the auth data below, the Twitter app "GitHub CI Test App" has
@@ -91,17 +93,41 @@ const defaultConfiguration = {
9193
}),
9294
};
9395

94-
const openConnections = {};
96+
const openConnections = new Set();
9597
let parseServer;
9698

99+
const destroyConnections = () => {
100+
for (const socket of openConnections.values()) {
101+
socket.destroy();
102+
}
103+
openConnections.clear();
104+
};
105+
106+
const shutdownServer = async _parseServer => {
107+
const closePromise = resolvingPromise();
108+
_parseServer.server.on('close', () => {
109+
closePromise.resolve();
110+
});
111+
await Promise.all([
112+
_parseServer.config.databaseController.adapter.handleShutdown(),
113+
_parseServer.liveQueryServer.shutdown(),
114+
]);
115+
_parseServer.server.close(error => {
116+
if (error) {
117+
console.error('Failed to close Parse Server', error);
118+
}
119+
});
120+
destroyConnections();
121+
await closePromise;
122+
expect(openConnections.size).toBe(0);
123+
parseServer = undefined;
124+
};
125+
97126
const reconfigureServer = async (changedConfiguration = {}) => {
98127
if (parseServer) {
99-
await parseServer.handleShutdown();
100-
await new Promise(resolve => parseServer.server.close(resolve));
101-
parseServer = undefined;
128+
await shutdownServer(parseServer);
102129
return reconfigureServer(changedConfiguration);
103130
}
104-
105131
didChangeConfiguration = Object.keys(changedConfiguration).length !== 0;
106132
const newConfiguration = Object.assign({}, defaultConfiguration, changedConfiguration || {}, {
107133
mountPath,
@@ -113,8 +139,7 @@ const reconfigureServer = async (changedConfiguration = {}) => {
113139
return reconfigureServer(newConfiguration);
114140
}
115141
const app = parseServer.expressApp;
116-
for (const fileName of ['parse.js', 'parse.min.js']) {
117-
const file = fs.readFileSync(path.resolve(__dirname, `./../../dist/${fileName}`)).toString();
142+
for (const [fileName, file] of Object.entries(distFiles)) {
118143
app.get(`/${fileName}`, (_req, res) => {
119144
res.send(`<html><head>
120145
<meta charset="utf-8">
@@ -132,17 +157,10 @@ const reconfigureServer = async (changedConfiguration = {}) => {
132157
</body></html>`);
133158
});
134159
}
135-
app.get('/clear/:fast', (req, res) => {
136-
const { fast } = req.params;
137-
TestUtils.destroyAllDataPermanently(fast).then(() => {
138-
res.send('{}');
139-
});
140-
});
141160
parseServer.server.on('connection', connection => {
142-
const key = `${connection.remoteAddress}:${connection.remotePort}`;
143-
openConnections[key] = connection;
161+
openConnections.add(connection);
144162
connection.on('close', () => {
145-
delete openConnections[key];
163+
openConnections.delete(connection);
146164
});
147165
});
148166
return parseServer;
@@ -155,12 +173,21 @@ global.Container = Parse.Object.extend('Container');
155173
global.TestPoint = Parse.Object.extend('TestPoint');
156174
global.TestObject = Parse.Object.extend('TestObject');
157175
global.reconfigureServer = reconfigureServer;
176+
global.shutdownServer = shutdownServer;
177+
global.openConnections = openConnections;
158178

159179
beforeAll(async () => {
180+
const promise = ['parse.js', 'parse.min.js'].map(fileName => {
181+
return fs.readFile(path.resolve(__dirname, `./../../dist/${fileName}`), 'utf8').then(file => {
182+
distFiles[fileName] = file;
183+
});
184+
});
185+
await Promise.all(promise);
160186
await reconfigureServer();
161187
Parse.initialize('integration');
162188
Parse.CoreManager.set('SERVER_URL', serverURL);
163189
Parse.CoreManager.set('MASTER_KEY', 'notsosecret');
190+
Parse.CoreManager.set('REQUEST_ATTEMPT_LIMIT', 1);
164191
});
165192

166193
afterEach(async () => {
@@ -172,11 +199,4 @@ afterEach(async () => {
172199
}
173200
});
174201

175-
afterAll(() => {
176-
// Jasmine process counts as one open connection
177-
if (Object.keys(openConnections).length > 1) {
178-
console.warn('There were open connections to the server left after the test finished');
179-
}
180-
});
181-
182202
module.exports = { twitterAuthData };

jasmine.json

+1-2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,5 @@
66
"spec_files": [
77
"*Test.js"
88
],
9-
"random": true,
10-
"timeout": 20000
9+
"random": true
1110
}

0 commit comments

Comments
 (0)