1

I'm trying to write a test for my application, where by I've used express-brute to prevent brute force attacks.

I have the following test:

it('should return 429 status after 1000 attempts', function (done) {
    this.timeout(5000);

    var counter = 0;

    var makeRequest = function (count, done) {
        counter++;
        request(app)
        .post('/login')
        .send({ username: 'a+' + count + '@b.com', password: 'wrong' + count })
        .end(function (err, res) {

            if (err) {
                console.log('failed request #', counter); 
                return done(err);
            }

            if (counter < 1001) {
                makeRequest(counter, done);
            }
            else {
                res.header.location.should.equal('/account/login');
                res.statusCode.should.equal(429);
                done();
            }
        });
    }

    makeRequest(counter, done);
});

Which throws either error:

Error: socket hang up sometimes it is Error: read ECONNRESET

It's always around connection # 225

The same test (with only 20 or so requests) works fine (if i change my express-brute config)

What's causing it to error out?

Am I not closing / disposing the connections correctly?

Alex
  • 37,502
  • 51
  • 204
  • 332

2 Answers2

2

What operating system do you use?

It may be necessary to increase the amount of allowed open sockets.

For example see here: How to increase limits on sockets on osx for load testing?

Community
  • 1
  • 1
bodokaiser
  • 15,122
  • 22
  • 97
  • 140
  • I'm glad you asked this; On windows, it seems to work fine. On OSX, I have this problem.... I thought I was going mad! – Alex Mar 08 '14 at 21:04
  • Yeah, the answer listed on that question does the trick... just annoying that I have to do that on every dev machine :-s – Alex Mar 08 '14 at 21:17
  • @Alex glad you found the problem! Is it then necessary to have so much connections for development? – bodokaiser Mar 09 '14 at 13:37
0

I was able to replicate a resource exhaustion problem by using this code, which I believe replicates the essentials of your problem:

var request = require("supertest");
var express = require("express");

var app = express();

app.post('/login',
    function (req, res, next) {
        res.send('Success!');
    }
);

var server = app.listen();

var counter = 0;

function makeRequest(count, done) {
    counter++;
    request(app)
        .post('/login')
        .send({ username: 'a+' + count + '@b.com', password: 'wrong' + count })
        .end(function (err, res) {

            if (err) {
                console.log('failed request #', counter);
                done(err);
            }

            if (counter < 1001) {
                console.log(counter);
                makeRequest(counter, done);
            }
            else {
                console.log(res);
                done();
            }
        });
}

function done(err) {
    process.exit(1);
}

makeRequest(counter, done);

And running it like this:

$ (ulimit -n 100; node test.js )

I have to use ulimit because whatever causes your problem does not happen on my OS. The ulimit command limits the number of open files to 100. When I run it like above, request number 89 fails. (There are a bunch of other files opened to run the script, which explains why it fails at request 89 rather than 100.)

I can get the code to run to completion if I change the code so that I create a server from my app:

var app = express();
// ...
var server = app.listen();

and I use server in request instead of app:

request(server)
    .post('/login')
// ...

So using what app.listen() returns should fix the issue.

Louis
  • 146,715
  • 28
  • 274
  • 320