Description
Issue Description
Under Windows, when running the test suite for parse-server, many of the tests will fail with the following error message:
Failed: There were open connections to the server left after the test finished
However, running the exact same test suite under Linux (in my case, I tried it on Debian amd64), the tests pass fine.
When running all of the tests, about 60% of them will fail with this error message. I'll explain my theory why below but this is not a small issue by any means.
Steps to reproduce
- Clone parse-server repository.
- Run
npm install
in the directory. - Run
npm run test:win
for Windows and the errors should appear. - If you are testing on Linux, you do
npm run test
ornpm test
/
Expected Results
This error message occurs with many files so I just picked one test file where this occurred and debugged that. The first test file ran is AccountLockoutPolicy.spec.js
and the very first test account should not be locked even after failed login attempts if account lockout policy is not set
fails on Windows.
For either Linux or Windows, the expectation is for the tests to pass. Here is the output for Linux when testing just the AccountLockoutPolicy.spec.js
test file. Note that I stop it halfway through because I am focusing on that first test.
Jasmine started
1
2
3
Open connection127.0.0.1:45278
Close connection127.0.0.1:45278
4
Open connection127.0.0.1:45280
Close connection127.0.0.1:45280
5
Open connection127.0.0.1:45284
Close connection127.0.0.1:45284
6
Open connection127.0.0.1:45286
Close connection127.0.0.1:45286
6.1
6.2
Open connection127.0.0.1:45288
Close connection127.0.0.1:45288
Account Lockout Policy:
✓ account should not be locked even after failed login attempts if account lockout policy is not set
✓ throw error if duration is set to an invalid number
✓ throw error if threshold is set to an invalid number
✓ throw error if threshold is < 1
✓ throw error if threshold is > 999
✓ throw error if duration is <= 0
✓ throw error if duration is > 99999
Open connection127.0.0.1:45290
Close connection127.0.0.1:45290
Open connection127.0.0.1:45296
Close connection127.0.0.1:45296
Open connection127.0.0.1:45298
Close connection127.0.0.1:45298
Open connection127.0.0.1:45300
Close connection127.0.0.1:45300
Open connection127.0.0.1:45302
Close connection127.0.0.1:45302
✓ lock account if failed login attempts are above threshold
Open connection127.0.0.1:45304
Close connection127.0.0.1:45304
Open connection127.0.0.1:45306
^C
On Windows, here is the result running the tests on the same file:
Jasmine started
1
2
3
Open connection127.0.0.1:5331
4
Close connection127.0.0.1:5331
Open connection127.0.0.1:5332
5
Close connection127.0.0.1:5332
Open connection127.0.0.1:5333
6
Close connection127.0.0.1:5333
Open connection127.0.0.1:5334
6.1
6.2
Close connection127.0.0.1:5334
Open connection127.0.0.1:5335
Account Lockout Policy:
× account should not be locked even after failed login attempts if account lockout policy is not set
- Failed: There were open connections to the server left after the test finished
Close connection127.0.0.1:5335
Terminate batch job (Y/N)? Y
What I think the issue is
When digging into the code to diagnose this issue, I started with the error message and what it indicates. In spec/helper.js
, lines 198-201 are the following:
const afterLogOut = () => {
console.log("afterLogOut: 1");
if (Object.keys(openConnections).length > 0) {
fail('There were open connections to the server left after the test finished');
}
So there is an array of open connections and if that is not empty at the end of the test, then something is still running or having issues. So, the next step was I found where openConnections was changed. Lines 143-150 in the same helper file are:
server = parseServer.server;
server.on('connection', connection => {
const key = `${connection.remoteAddress}:${connection.remotePort}`;
openConnections[key] = connection;
console.log("Open connection" + key);
console.trace();
connection.on('close', () => { console.log("Close connection" + key); console.trace(); delete openConnections[key]; });
});
If you take a look at the logs given above, for Linux the connection is opened and closed almost immediately which is what you expect for HTTP requests. However, Windows has a bit of a lag and this is what causes the error. When the open connections are checked, there is still an open connection because it has not been closed yet.
Sample test case
I was not sure if the error was related to Parse or a bug in XMLHttpRequest so I created a test script to determine if the same thing occurs with XMLHttpRequest.
Here is my test script where the same issue still occurs:
var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest,
express = require('express'),
http = require('http'),
Url = require("url");
function makeRequest (method, url) {
return new Promise(function (resolve, reject) {
var xhr = new XMLHttpRequest();
var handled = false;
xhr.onreadystatechange = function() {
if (xhr.readyState !== 4 || handled) {
return;
}
handled = true;
console.log("ajax: 1", xhr.readyState);
resolve(xhr.responseText, xhr.status, xhr);
console.log("ajax: 2", xhr.readyState);
};
xhr.open(method, url, true);
xhr.send();
});
}
var app = express();
var sockets = {};
var server = app.listen(1337, 'localhost', () => console.log('Example app listening on port 1337!'));
app.get('/', (req, res) => res.send('Hello World!'));
server.on('connection', (socket) => {
const socketId = socket.remoteAddress + ':' + socket.remotePort;
sockets[socketId] = socket;
console.log("Open socket", socketId);
socket.on('close', () => {
console.log("Close socket", socketId);
delete sockets[socketId];
});
});
// Example:
makeRequest('GET', 'http://localhost:1337').then(function (response, status, hdr) {
console.log("If the connection is not closed here, there is probably an issue...");
console.log(response, status, hdr);
}).catch(function (e) {
console.error('Augh, there was an error!', e);
}).then(function() {
return new Promise((resolve) => {
setTimeout(() => {
console.log("\nFinished. Closing server");
server.close();
resolve();
}, 3000);
});
});
On Linux, the connection is opened and closed almost instantly but there is a lag once again in Windows.
Solution
What would be the best way to solve this? We could put a delay in checking the open connections for Windows? Or is there another solution I am missing?
Environment Setup
- Server
- parse-server version (Be specific! Don't say 'latest'.) : 2.6.5
- Operating System: Windows 10 x64
- Localhost or remote server? (AWS, Heroku, Azure, Digital Ocean, etc): Localhost