var util = require('util'); var EventEmitter = require('events').EventEmitter; var libDir = __dirname + '/../../../lib'; var defaults = require(libDir + '/defaults'); var pools = require(libDir + '/pool'); var poolId = 0; require(__dirname + '/../../test-helper'); var FakeClient = function() { EventEmitter.call(this); } util.inherits(FakeClient, EventEmitter); FakeClient.prototype.connect = function(cb) { process.nextTick(cb); } FakeClient.prototype.end = function() { this.endCalled = true; } //Hangs the event loop until 'end' is called on client var HangingClient = function(config) { EventEmitter.call(this); this.config = config; } util.inherits(HangingClient, EventEmitter); HangingClient.prototype.connect = function(cb) { this.intervalId = setInterval(function() { console.log('hung client...'); }, 1000); process.nextTick(cb); } HangingClient.prototype.end = function() { clearInterval(this.intervalId); } pools.Client = FakeClient; test('no pools exist', function() { assert.empty(Object.keys(pools.all)); }); test('pool creates pool on miss', function() { var p = pools.getOrCreate(); assert.ok(p); assert.equal(Object.keys(pools.all).length, 1); var p2 = pools.getOrCreate(); assert.equal(p, p2); assert.equal(Object.keys(pools.all).length, 1); var p3 = pools.getOrCreate("postgres://postgres:password@localhost:5432/postgres"); assert.notEqual(p, p3); assert.equal(Object.keys(pools.all).length, 2); }); test('pool follows defaults', function() { var p = pools.getOrCreate(poolId++); for(var i = 0; i < 100; i++) { p.acquire(function(err, client) { }); } assert.equal(p.getPoolSize(), defaults.poolSize); }); test('pool#connect with 3 parameters', function() { var p = pools.getOrCreate(poolId++); var tid = setTimeout(function() { throw new Error("Connection callback was never called"); }, 100); p.connect(function(err, client, done) { clearTimeout(tid); assert.ifError(err, null); assert.ok(client); assert.equal(p.availableObjectsCount(), 0); assert.equal(p.getPoolSize(), 1); client.emit('drain'); assert.equal(p.availableObjectsCount(), 0); assert.equal(p.getPoolSize(), 1); done(); assert.equal(p.availableObjectsCount(), 1); assert.equal(p.getPoolSize(), 1); p.destroyAllNow(); }); }); test('on client error, client is removed from pool', function() { var p = pools.getOrCreate(poolId++); p.connect(assert.success(function(client, done) { assert.ok(client); done(); assert.equal(p.availableObjectsCount(), 1); assert.equal(p.getPoolSize(), 1); //error event fires on pool BEFORE pool.destroy is called with client assert.emits(p, 'error', function(err) { assert.equal(err.message, 'test error'); assert.ok(!client.endCalled); assert.equal(p.availableObjectsCount(), 1); assert.equal(p.getPoolSize(), 1); //after we're done in our callback, pool.destroy is called process.nextTick(function() { assert.ok(client.endCalled); assert.equal(p.availableObjectsCount(), 0); assert.equal(p.getPoolSize(), 0); p.destroyAllNow(); }); }); client.emit('error', new Error('test error')); })); }); test('pool with connection error on connection', function() { pools.Client = function() { return { connect: function(cb) { process.nextTick(function() { cb(new Error('Could not connect')); }); }, on: Function.prototype }; }; test('two parameters', function() { var p = pools.getOrCreate(poolId++); p.connect(assert.calls(function(err, client) { assert.ok(err); assert.equal(client, null); //client automatically removed assert.equal(p.availableObjectsCount(), 0); assert.equal(p.getPoolSize(), 0); })); }); test('three parameters', function() { var p = pools.getOrCreate(poolId++); var tid = setTimeout(function() { assert.fail('Did not call connect callback'); }, 100); p.connect(function(err, client, done) { clearTimeout(tid); assert.ok(err); assert.equal(client, null); //done does nothing done(new Error('OH NOOOO')); done(); assert.equal(p.availableObjectsCount(), 0); assert.equal(p.getPoolSize(), 0); }); }); }); test('returnning an error to done()', function() { var p = pools.getOrCreate(poolId++); pools.Client = FakeClient; p.connect(function(err, client, done) { assert.equal(err, null); assert(client); done(new Error("BROKEN")); assert.equal(p.availableObjectsCount(), 0); assert.equal(p.getPoolSize(), 0); }); }); test('fetching pool by object', function() { var p = pools.getOrCreate({ user: 'brian', host: 'localhost', password: 'password' }); var p2 = pools.getOrCreate({ user: 'brian', host: 'localhost', password: 'password' }); assert.equal(p, p2); }); test('pool#connect client.poolCount', function() { var p = pools.getOrCreate(poolId++); var tid; setConnectTimeout = function() { tid = setTimeout(function() { throw new Error("Connection callback was never called"); }, 100); } setConnectTimeout(); p.connect(function(err, client, done) { clearTimeout(tid); assert.equal(client.poolCount, 1, 'after connect, poolCount should be 1'); done(); assert.equal(client.poolCount, 1, 'after returning client to pool, poolCount should still be 1'); setConnectTimeout(); p.connect(function(err, client, done) { clearTimeout(tid); assert.equal(client.poolCount, 2, 'after second connect, poolCount should be 2'); done(); setConnectTimeout(); p.destroyAllNow(function() { clearTimeout(tid); assert.equal(client.poolCount, undefined, 'after pool is destroyed, count should be undefined'); }); }) }); });