UNPKG

6.99 kBJavaScriptView Raw
1'use strict'
2const net = require('net')
3const co = require('co')
4const expect = require('expect.js')
5
6const describe = require('mocha').describe
7const it = require('mocha').it
8
9const Pool = require('../')
10
11describe('pool error handling', function () {
12 it('Should complete these queries without dying', function (done) {
13 const pool = new Pool()
14 let errors = 0
15 let shouldGet = 0
16 function runErrorQuery() {
17 shouldGet++
18 return new Promise(function (resolve, reject) {
19 pool.query("SELECT 'asd'+1 ").then(function (res) {
20 reject(res) // this should always error
21 }).catch(function (err) {
22 errors++
23 resolve(err)
24 })
25 })
26 }
27 const ps = []
28 for (let i = 0; i < 5; i++) {
29 ps.push(runErrorQuery())
30 }
31 Promise.all(ps).then(function () {
32 expect(shouldGet).to.eql(errors)
33 pool.end(done)
34 })
35 })
36
37 describe('calling release more than once', () => {
38 it('should throw each time', co.wrap(function* () {
39 const pool = new Pool()
40 const client = yield pool.connect()
41 client.release()
42 expect(() => client.release()).to.throwError()
43 expect(() => client.release()).to.throwError()
44 return yield pool.end()
45 }))
46
47 it('should throw each time with callbacks', function (done) {
48 const pool = new Pool()
49
50 pool.connect(function (err, client, clientDone) {
51 expect(err).not.to.be.an(Error)
52 clientDone()
53
54 expect(() => clientDone()).to.throwError()
55 expect(() => clientDone()).to.throwError()
56
57 pool.end(done)
58 })
59 })
60 })
61
62 describe('calling connect after end', () => {
63 it('should return an error', function* () {
64 const pool = new Pool()
65 const res = yield pool.query('SELECT $1::text as name', ['hi'])
66 expect(res.rows[0].name).to.equal('hi')
67 const wait = pool.end()
68 pool.query('select now()')
69 yield wait
70 expect(() => pool.query('select now()')).to.reject()
71 })
72 })
73
74 describe('using an ended pool', () => {
75 it('rejects all additional promises', (done) => {
76 const pool = new Pool()
77 const promises = []
78 pool.end()
79 .then(() => {
80 const squash = promise => promise.catch(e => 'okay!')
81 promises.push(squash(pool.connect()))
82 promises.push(squash(pool.query('SELECT NOW()')))
83 promises.push(squash(pool.end()))
84 Promise.all(promises).then(res => {
85 expect(res).to.eql(['okay!', 'okay!', 'okay!'])
86 done()
87 })
88 })
89 })
90
91 it('returns an error on all additional callbacks', (done) => {
92 const pool = new Pool()
93 pool.end(() => {
94 pool.query('SELECT *', (err) => {
95 expect(err).to.be.an(Error)
96 pool.connect((err) => {
97 expect(err).to.be.an(Error)
98 pool.end((err) => {
99 expect(err).to.be.an(Error)
100 done()
101 })
102 })
103 })
104 })
105 })
106 })
107
108 describe('error from idle client', () => {
109 it('removes client from pool', co.wrap(function* () {
110 const pool = new Pool()
111 const client = yield pool.connect()
112 expect(pool.totalCount).to.equal(1)
113 expect(pool.waitingCount).to.equal(0)
114 expect(pool.idleCount).to.equal(0)
115 client.release()
116 yield new Promise((resolve, reject) => {
117 process.nextTick(() => {
118 let poolError
119 pool.once('error', (err) => {
120 poolError = err
121 })
122
123 let clientError
124 client.once('error', (err) => {
125 clientError = err
126 })
127
128 client.emit('error', new Error('expected'))
129
130 expect(clientError.message).to.equal('expected')
131 expect(poolError.message).to.equal('expected')
132 expect(pool.idleCount).to.equal(0)
133 expect(pool.totalCount).to.equal(0)
134 pool.end().then(resolve, reject)
135 })
136 })
137 }))
138 })
139
140 describe('error from in-use client', () => {
141 it('keeps the client in the pool', co.wrap(function* () {
142 const pool = new Pool()
143 const client = yield pool.connect()
144 expect(pool.totalCount).to.equal(1)
145 expect(pool.waitingCount).to.equal(0)
146 expect(pool.idleCount).to.equal(0)
147
148 yield new Promise((resolve, reject) => {
149 process.nextTick(() => {
150 let poolError
151 pool.once('error', (err) => {
152 poolError = err
153 })
154
155 let clientError
156 client.once('error', (err) => {
157 clientError = err
158 })
159
160 client.emit('error', new Error('expected'))
161
162 expect(clientError.message).to.equal('expected')
163 expect(poolError).not.to.be.ok()
164 expect(pool.idleCount).to.equal(0)
165 expect(pool.totalCount).to.equal(1)
166 client.release()
167 pool.end().then(resolve, reject)
168 })
169 })
170 }))
171 })
172
173 describe('passing a function to pool.query', () => {
174 it('calls back with error', (done) => {
175 const pool = new Pool()
176 console.log('passing fn to query')
177 pool.query((err) => {
178 expect(err).to.be.an(Error)
179 pool.end(done)
180 })
181 })
182 })
183
184 describe('pool with lots of errors', () => {
185 it('continues to work and provide new clients', co.wrap(function* () {
186 const pool = new Pool({ max: 1 })
187 const errors = []
188 for (var i = 0; i < 20; i++) {
189 try {
190 yield pool.query('invalid sql')
191 } catch (err) {
192 errors.push(err)
193 }
194 }
195 expect(errors).to.have.length(20)
196 expect(pool.idleCount).to.equal(0)
197 expect(pool.query).to.be.a(Function)
198 const res = yield pool.query('SELECT $1::text as name', ['brianc'])
199 expect(res.rows).to.have.length(1)
200 expect(res.rows[0].name).to.equal('brianc')
201 return pool.end()
202 }))
203 })
204
205 it('should continue with queued items after a connection failure', (done) => {
206 const closeServer = net.createServer((socket) => {
207 socket.destroy()
208 }).unref()
209
210 closeServer.listen(() => {
211 const pool = new Pool({ max: 1, port: closeServer.address().port, host: 'localhost' })
212 pool.connect((err) => {
213 expect(err).to.be.an(Error)
214 if (err.errno) {
215 expect(err.errno).to.be('ECONNRESET')
216 }
217 })
218 pool.connect((err) => {
219 expect(err).to.be.an(Error)
220 if (err.errno) {
221 expect(err.errno).to.be('ECONNRESET')
222 }
223 closeServer.close(() => {
224 pool.end(done)
225 })
226 })
227 })
228 })
229
230 it('handles post-checkout client failures in pool.query', (done) => {
231 const pool = new Pool({ max: 1 })
232 pool.on('error', () => {
233 // We double close the connection in this test, prevent exception caused by that
234 })
235 pool.query('SELECT pg_sleep(5)', [], (err) => {
236 expect(err).to.be.an(Error)
237 done()
238 })
239
240 setTimeout(() => {
241 pool._clients[0].end()
242 }, 1000)
243 })
244})