| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260 | 'use strict'const net = require('net')const co = require('co')const expect = require('expect.js')const describe = require('mocha').describeconst it = require('mocha').itconst 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)    })  })  it('Catches errors in client.query', async function () {    let caught = false    const pool = new Pool()    try {      await pool.query(null)    } catch (e) {      caught = true    }    pool.end()    expect(caught).to.be(true)  })  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)  })})
 |