index.js 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. 'use strict'
  2. const expect = require('expect.js')
  3. const _ = require('lodash')
  4. const describe = require('mocha').describe
  5. const it = require('mocha').it
  6. const Pool = require('../')
  7. describe('pool', function () {
  8. describe('with callbacks', function () {
  9. it('works totally unconfigured', function (done) {
  10. const pool = new Pool()
  11. pool.connect(function (err, client, release) {
  12. if (err) return done(err)
  13. client.query('SELECT NOW()', function (err, res) {
  14. release()
  15. if (err) return done(err)
  16. expect(res.rows).to.have.length(1)
  17. pool.end(done)
  18. })
  19. })
  20. })
  21. it('passes props to clients', function (done) {
  22. const pool = new Pool({ binary: true })
  23. pool.connect(function (err, client, release) {
  24. release()
  25. if (err) return done(err)
  26. expect(client.binary).to.eql(true)
  27. pool.end(done)
  28. })
  29. })
  30. it('can run a query with a callback without parameters', function (done) {
  31. const pool = new Pool()
  32. pool.query('SELECT 1 as num', function (err, res) {
  33. expect(res.rows[0]).to.eql({ num: 1 })
  34. pool.end(function () {
  35. done(err)
  36. })
  37. })
  38. })
  39. it('can run a query with a callback', function (done) {
  40. const pool = new Pool()
  41. pool.query('SELECT $1::text as name', ['brianc'], function (err, res) {
  42. expect(res.rows[0]).to.eql({ name: 'brianc' })
  43. pool.end(function () {
  44. done(err)
  45. })
  46. })
  47. })
  48. it('passes connection errors to callback', function (done) {
  49. const pool = new Pool({ port: 53922 })
  50. pool.query('SELECT $1::text as name', ['brianc'], function (err, res) {
  51. expect(res).to.be(undefined)
  52. expect(err).to.be.an(Error)
  53. // a connection error should not polute the pool with a dead client
  54. expect(pool.totalCount).to.equal(0)
  55. pool.end(function (err) {
  56. done(err)
  57. })
  58. })
  59. })
  60. it('does not pass client to error callback', function (done) {
  61. const pool = new Pool({ port: 58242 })
  62. pool.connect(function (err, client, release) {
  63. expect(err).to.be.an(Error)
  64. expect(client).to.be(undefined)
  65. expect(release).to.be.a(Function)
  66. pool.end(done)
  67. })
  68. })
  69. it('removes client if it errors in background', function (done) {
  70. const pool = new Pool()
  71. pool.connect(function (err, client, release) {
  72. release()
  73. if (err) return done(err)
  74. client.testString = 'foo'
  75. setTimeout(function () {
  76. client.emit('error', new Error('on purpose'))
  77. }, 10)
  78. })
  79. pool.on('error', function (err) {
  80. expect(err.message).to.be('on purpose')
  81. expect(err.client).to.not.be(undefined)
  82. expect(err.client.testString).to.be('foo')
  83. err.client.connection.stream.on('end', function () {
  84. pool.end(done)
  85. })
  86. })
  87. })
  88. it('should not change given options', function (done) {
  89. const options = { max: 10 }
  90. const pool = new Pool(options)
  91. pool.connect(function (err, client, release) {
  92. release()
  93. if (err) return done(err)
  94. expect(options).to.eql({ max: 10 })
  95. pool.end(done)
  96. })
  97. })
  98. it('does not create promises when connecting', function (done) {
  99. const pool = new Pool()
  100. const returnValue = pool.connect(function (err, client, release) {
  101. release()
  102. if (err) return done(err)
  103. pool.end(done)
  104. })
  105. expect(returnValue).to.be(undefined)
  106. })
  107. it('does not create promises when querying', function (done) {
  108. const pool = new Pool()
  109. const returnValue = pool.query('SELECT 1 as num', function (err) {
  110. pool.end(function () {
  111. done(err)
  112. })
  113. })
  114. expect(returnValue).to.be(undefined)
  115. })
  116. it('does not create promises when ending', function (done) {
  117. const pool = new Pool()
  118. const returnValue = pool.end(done)
  119. expect(returnValue).to.be(undefined)
  120. })
  121. it('never calls callback syncronously', function (done) {
  122. const pool = new Pool()
  123. pool.connect((err, client) => {
  124. if (err) throw err
  125. client.release()
  126. setImmediate(() => {
  127. let called = false
  128. pool.connect((err, client) => {
  129. if (err) throw err
  130. called = true
  131. client.release()
  132. setImmediate(() => {
  133. pool.end(done)
  134. })
  135. })
  136. expect(called).to.equal(false)
  137. })
  138. })
  139. })
  140. })
  141. describe('with promises', function () {
  142. it('connects, queries, and disconnects', function () {
  143. const pool = new Pool()
  144. return pool.connect().then(function (client) {
  145. return client.query('select $1::text as name', ['hi']).then(function (res) {
  146. expect(res.rows).to.eql([{ name: 'hi' }])
  147. client.release()
  148. return pool.end()
  149. })
  150. })
  151. })
  152. it('executes a query directly', () => {
  153. const pool = new Pool()
  154. return pool.query('SELECT $1::text as name', ['hi']).then((res) => {
  155. expect(res.rows).to.have.length(1)
  156. expect(res.rows[0].name).to.equal('hi')
  157. return pool.end()
  158. })
  159. })
  160. it('properly pools clients', function () {
  161. const pool = new Pool({ poolSize: 9 })
  162. const promises = _.times(30, function () {
  163. return pool.connect().then(function (client) {
  164. return client.query('select $1::text as name', ['hi']).then(function (res) {
  165. client.release()
  166. return res
  167. })
  168. })
  169. })
  170. return Promise.all(promises).then(function (res) {
  171. expect(res).to.have.length(30)
  172. expect(pool.totalCount).to.be(9)
  173. return pool.end()
  174. })
  175. })
  176. it('supports just running queries', function () {
  177. const pool = new Pool({ poolSize: 9 })
  178. const text = 'select $1::text as name'
  179. const values = ['hi']
  180. const query = { text: text, values: values }
  181. const promises = _.times(30, () => pool.query(query))
  182. return Promise.all(promises).then(function (queries) {
  183. expect(queries).to.have.length(30)
  184. return pool.end()
  185. })
  186. })
  187. it('recovers from query errors', function () {
  188. const pool = new Pool()
  189. const errors = []
  190. const promises = _.times(30, () => {
  191. return pool.query('SELECT asldkfjasldkf').catch(function (e) {
  192. errors.push(e)
  193. })
  194. })
  195. return Promise.all(promises).then(() => {
  196. expect(errors).to.have.length(30)
  197. expect(pool.totalCount).to.equal(0)
  198. expect(pool.idleCount).to.equal(0)
  199. return pool.query('SELECT $1::text as name', ['hi']).then(function (res) {
  200. expect(res.rows).to.eql([{ name: 'hi' }])
  201. return pool.end()
  202. })
  203. })
  204. })
  205. })
  206. })