UNPKG

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