123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249 |
- 'use strict'
- const net = require('net')
- const co = require('co')
- const expect = require('expect.js')
- const describe = require('mocha').describe
- const it = require('mocha').it
- const Pool = require('../')
- describe('pool error handling', function () {
- it('Should complete these queries without dying', function (done) {
- const pool = new Pool()
- let errors = 0
- let shouldGet = 0
- function runErrorQuery() {
- shouldGet++
- return new Promise(function (resolve, reject) {
- pool
- .query("SELECT 'asd'+1 ")
- .then(function (res) {
- reject(res) // this should always error
- })
- .catch(function (err) {
- errors++
- resolve(err)
- })
- })
- }
- const ps = []
- for (let i = 0; i < 5; i++) {
- ps.push(runErrorQuery())
- }
- Promise.all(ps).then(function () {
- expect(shouldGet).to.eql(errors)
- pool.end(done)
- })
- })
- describe('calling release more than once', () => {
- it(
- 'should throw each time',
- co.wrap(function* () {
- const pool = new Pool()
- const client = yield pool.connect()
- client.release()
- expect(() => client.release()).to.throwError()
- expect(() => client.release()).to.throwError()
- return yield pool.end()
- })
- )
- it('should throw each time with callbacks', function (done) {
- const pool = new Pool()
- pool.connect(function (err, client, clientDone) {
- expect(err).not.to.be.an(Error)
- clientDone()
- expect(() => clientDone()).to.throwError()
- expect(() => clientDone()).to.throwError()
- pool.end(done)
- })
- })
- })
- describe('using an ended pool', () => {
- it('rejects all additional promises', (done) => {
- const pool = new Pool()
- const promises = []
- pool.end().then(() => {
- const squash = (promise) => promise.catch((e) => 'okay!')
- promises.push(squash(pool.connect()))
- promises.push(squash(pool.query('SELECT NOW()')))
- promises.push(squash(pool.end()))
- Promise.all(promises).then((res) => {
- expect(res).to.eql(['okay!', 'okay!', 'okay!'])
- done()
- })
- })
- })
- it('returns an error on all additional callbacks', (done) => {
- const pool = new Pool()
- pool.end(() => {
- pool.query('SELECT *', (err) => {
- expect(err).to.be.an(Error)
- pool.connect((err) => {
- expect(err).to.be.an(Error)
- pool.end((err) => {
- expect(err).to.be.an(Error)
- done()
- })
- })
- })
- })
- })
- })
- describe('error from idle client', () => {
- it(
- 'removes client from pool',
- co.wrap(function* () {
- const pool = new Pool()
- const client = yield pool.connect()
- expect(pool.totalCount).to.equal(1)
- expect(pool.waitingCount).to.equal(0)
- expect(pool.idleCount).to.equal(0)
- client.release()
- yield new Promise((resolve, reject) => {
- process.nextTick(() => {
- let poolError
- pool.once('error', (err) => {
- poolError = err
- })
- let clientError
- client.once('error', (err) => {
- clientError = err
- })
- client.emit('error', new Error('expected'))
- expect(clientError.message).to.equal('expected')
- expect(poolError.message).to.equal('expected')
- expect(pool.idleCount).to.equal(0)
- expect(pool.totalCount).to.equal(0)
- pool.end().then(resolve, reject)
- })
- })
- })
- )
- })
- describe('error from in-use client', () => {
- it(
- 'keeps the client in the pool',
- co.wrap(function* () {
- const pool = new Pool()
- const client = yield pool.connect()
- expect(pool.totalCount).to.equal(1)
- expect(pool.waitingCount).to.equal(0)
- expect(pool.idleCount).to.equal(0)
- yield new Promise((resolve, reject) => {
- process.nextTick(() => {
- let poolError
- pool.once('error', (err) => {
- poolError = err
- })
- let clientError
- client.once('error', (err) => {
- clientError = err
- })
- client.emit('error', new Error('expected'))
- expect(clientError.message).to.equal('expected')
- expect(poolError).not.to.be.ok()
- expect(pool.idleCount).to.equal(0)
- expect(pool.totalCount).to.equal(1)
- client.release()
- pool.end().then(resolve, reject)
- })
- })
- })
- )
- })
- describe('passing a function to pool.query', () => {
- it('calls back with error', (done) => {
- const pool = new Pool()
- console.log('passing fn to query')
- pool.query((err) => {
- expect(err).to.be.an(Error)
- pool.end(done)
- })
- })
- })
- describe('pool with lots of errors', () => {
- it(
- 'continues to work and provide new clients',
- co.wrap(function* () {
- const pool = new Pool({ max: 1 })
- const errors = []
- for (var i = 0; i < 20; i++) {
- try {
- yield pool.query('invalid sql')
- } catch (err) {
- errors.push(err)
- }
- }
- expect(errors).to.have.length(20)
- expect(pool.idleCount).to.equal(0)
- expect(pool.query).to.be.a(Function)
- const res = yield pool.query('SELECT $1::text as name', ['brianc'])
- expect(res.rows).to.have.length(1)
- expect(res.rows[0].name).to.equal('brianc')
- return pool.end()
- })
- )
- })
- it('should continue with queued items after a connection failure', (done) => {
- const closeServer = net
- .createServer((socket) => {
- socket.destroy()
- })
- .unref()
- closeServer.listen(() => {
- const pool = new Pool({ max: 1, port: closeServer.address().port, host: 'localhost' })
- pool.connect((err) => {
- expect(err).to.be.an(Error)
- if (err.code) {
- expect(err.code).to.be('ECONNRESET')
- }
- })
- pool.connect((err) => {
- expect(err).to.be.an(Error)
- if (err.code) {
- expect(err.code).to.be('ECONNRESET')
- }
- closeServer.close(() => {
- pool.end(done)
- })
- })
- })
- })
- it('handles post-checkout client failures in pool.query', (done) => {
- const pool = new Pool({ max: 1 })
- pool.on('error', () => {
- // We double close the connection in this test, prevent exception caused by that
- })
- pool.query('SELECT pg_sleep(5)', [], (err) => {
- expect(err).to.be.an(Error)
- done()
- })
- setTimeout(() => {
- pool._clients[0].end()
- }, 1000)
- })
- })
|