[Pkg-javascript-commits] [node-finished] 04/10: Imported Upstream version 2.1.0

Andrew Kelley andrewrk-guest at moszumanska.debian.org
Fri Sep 12 04:47:44 UTC 2014


This is an automated email from the git hooks/post-receive script.

andrewrk-guest pushed a commit to branch master
in repository node-finished.

commit 157529b56ebc3767a19fbc0cf6b04e4f09aab8f0
Author: Andrew Kelley <superjoe30 at gmail.com>
Date:   Fri Sep 12 01:50:04 2014 +0000

    Imported Upstream version 2.1.0
---
 .gitignore   |   3 +
 .npmignore   |   3 -
 .travis.yml  |   2 +-
 HISTORY.md   |  36 +++--
 LICENSE      |  23 +++
 README.md    | 114 +++++++--------
 index.js     | 109 +++++++++++---
 package.json |  29 ++--
 test/test.js | 456 ++++++++++++++++++++++++++++++++++++++++++++++++-----------
 9 files changed, 587 insertions(+), 188 deletions(-)

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..df9af16
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+coverage
+node_modules
+npm-debug.log
diff --git a/.npmignore b/.npmignore
deleted file mode 100644
index cd39b77..0000000
--- a/.npmignore
+++ /dev/null
@@ -1,3 +0,0 @@
-coverage/
-test/
-.travis.yml
diff --git a/.travis.yml b/.travis.yml
index 1ff243c..6299766 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -8,4 +8,4 @@ matrix:
     - node_js: "0.11"
   fast_finish: true
 script: "npm run-script test-travis"
-after_script: "npm install coveralls at 2.10.0 && cat ./coverage/lcov.info | coveralls"
+after_script: "test $TRAVIS_NODE_VERSION = '0.10' && npm install coveralls at 2 && cat ./coverage/lcov.info | coveralls"
diff --git a/HISTORY.md b/HISTORY.md
index 8937250..0aa241b 100644
--- a/HISTORY.md
+++ b/HISTORY.md
@@ -1,48 +1,64 @@
+2.1.0 / 2014-08-16
+==================
+
+  * Check if `socket` is detached
+  * Return `undefined` for `isFinished` if state unknown
+
+2.0.0 / 2014-08-16
+==================
+
+  * Add `isFinished` function
+  * Move to `jshttp` organization
+  * Remove support for plain socket argument
+  * Rename to `on-finished`
+  * Support both `req` and `res` as arguments
+  * deps: ee-first at 1.0.5
+
 1.2.2 / 2014-06-10
-==========
+==================
 
-  * reduce listeners added to emitters
+  * Reduce listeners added to emitters
     - avoids "event emitter leak" warnings when used multiple times on same request
 
 1.2.1 / 2014-06-08
 ==================
 
-  * fix returned value when already finished
+  * Fix returned value when already finished
 
 1.2.0 / 2014-06-05
 ==================
 
-  * call callback when called on already-finished socket
+  * Call callback when called on already-finished socket
 
 1.1.4 / 2014-05-27
 ==================
 
-  * support node.js 0.8
+  * Support node.js 0.8
 
 1.1.3 / 2014-04-30
 ==================
 
-  * make sure errors passed as instanceof `Error`
+  * Make sure errors passed as instanceof `Error`
 
 1.1.2 / 2014-04-18
 ==================
 
-  * default the `socket` to passed-in object
+  * Default the `socket` to passed-in object
 
 1.1.1 / 2014-01-16
 ==================
 
-  * rename module to `finished`
+  * Rename module to `finished`
 
 1.1.0 / 2013-12-25
 ==================
 
-  * call callback when called on already-errored socket
+  * Call callback when called on already-errored socket
 
 1.0.1 / 2013-12-20
 ==================
 
-  * actually pass the error to the callback
+  * Actually pass the error to the callback
 
 1.0.0 / 2013-12-20
 ==================
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..5931fd2
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,23 @@
+(The MIT License)
+
+Copyright (c) 2013 Jonathan Ong <me at jongleberry.com>
+Copyright (c) 2014 Douglas Christopher Wilson <doug at somethingdoug.com>
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/README.md b/README.md
index 79facd5..887b5c3 100644
--- a/README.md
+++ b/README.md
@@ -1,88 +1,90 @@
-# finished
+# on-finished
 
-[![NPM Version](https://badge.fury.io/js/finished.svg)](http://badge.fury.io/js/finished)
-[![Build Status](https://travis-ci.org/expressjs/finished.svg?branch=master)](https://travis-ci.org/expressjs/finished)
-[![Coverage Status](https://img.shields.io/coveralls/expressjs/finished.svg?branch=master)](https://coveralls.io/r/expressjs/finished)
+[![NPM Version](http://img.shields.io/npm/v/on-finished.svg?style=flat)](https://www.npmjs.org/package/on-finished)
+[![Node.js Version](http://img.shields.io/badge/node.js->=_0.8-brightgreen.svg?style=flat)](http://nodejs.org/download/)
+[![Build Status](http://img.shields.io/travis/jshttp/on-finished.svg?style=flat)](https://travis-ci.org/jshttp/on-finished)
+[![Coverage Status](https://img.shields.io/coveralls/jshttp/on-finished.svg?style=flat)](https://coveralls.io/r/jshttp/on-finished)
 
 Execute a callback when a request closes, finishes, or errors.
 
-#### Install
+## Install
 
 ```sh
-$ npm install finished
+$ npm install on-finished
 ```
 
-#### Uses
+## API
 
-This is useful for cleaning up streams. For example, you want to destroy any file streams you create on socket errors otherwise you will leak file descriptors.
+```js
+var onFinished = require('on-finished')
+```
 
-This is required to fix what many perceive as issues with node's streams. Relevant:
+### onFinished(res, listener)
 
-- [node#6041](https://github.com/joyent/node/issues/6041)
-- [koa#184](https://github.com/koajs/koa/issues/184)
-- [koa#165](https://github.com/koajs/koa/issues/165)
+Attach a listener to listen for the response to finish. The listener will
+be invoked only once when the response finished. If the response finished
+to to an error, the first argument will contain the error.
 
-## API
-
-### finished(response, callback)
+Listening to the end of a response would be used to close things associated
+with the response, like open files.
 
 ```js
-var onFinished = require('finished')
-
 onFinished(res, function (err) {
-  // do something maybe
+  // clean up open fds, etc.
 })
 ```
 
-### Examples
+### onFinished(req, listener)
 
-The following code ensures that file descriptors are always closed once the response finishes.
+Attach a listener to listen for the request to finish. The listener will
+be invoked only once when the request finished. If the request finished
+to to an error, the first argument will contain the error.
 
-#### Node / Connect / Express
+Listening to the end of a request would be used to know when to continue
+after reading the data.
 
 ```js
-var onFinished = require('finished')
+var data = ''
 
-function (req, res, next) {
-  var stream = fs.createReadStream('thingie.json')
-  stream.pipe(res)
-  onFinished(res, function (err) {
-    stream.destroy()
-  })
-}
+req.setEncoding('utf8')
+res.on('data', function (str) {
+  data += str
+})
+
+onFinished(req, function (err) {
+  // data is read unless there is err
+})
 ```
 
-#### Koa
+### onFinished.isFinished(res)
 
-```js
-function* () {
-  var stream = this.body = fs.createReadStream('thingie.json')
-  onFinished(this, function (err) {
-    stream.destroy()
-  })
-}
-```
+Determine if `res` is already finished. This would be useful to check and
+not even start certain operations if the response has already finished.
 
-## License
+### onFinished.isFinished(req)
 
-The MIT License (MIT)
+Determine if `req` is already finished. This would be useful to check and
+not even start certain operations if the request has already finished.
 
-Copyright (c) 2013 Jonathan Ong me at jongleberry.com
+### Example
+
+The following code ensures that file descriptors are always closed
+once the response finishes.
+
+```js
+var destroy = require('destroy')
+var http = require('http')
+var onFinished = require('finished')
 
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
+http.createServer(function onRequest(req, res) {
+  var stream = fs.createReadStream('package.json')
+  stream.pipe(res)
+  onFinished(res, function (err) {
+    destroy(stream)
+  })
+})
+```
 
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
+## License
 
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
+[MIT](LICENSE)
diff --git a/index.js b/index.js
index 90709d4..a505561 100644
--- a/index.js
+++ b/index.js
@@ -1,10 +1,18 @@
 /*!
- * finished
- * Copyright(c) 2014 Jonathan Ong
+ * on-finished
+ * Copyright(c) 2013 Jonathan Ong
+ * Copyright(c) 2014 Douglas Christopher Wilson
  * MIT Licensed
  */
 
 /**
+ * Module exports.
+ */
+
+module.exports = onFinished;
+module.exports.isFinished = isFinished;
+
+/**
 * Module dependencies.
 */
 
@@ -23,40 +31,97 @@ var defer = typeof setImmediate === 'function'
  * Invoke callback when the response has finished, useful for
  * cleaning up resources afterwards.
  *
- * @param {object} thingie
- * @param {function} callback
+ * @param {object} msg
+ * @param {function} listener
  * @return {object}
  * @api public
  */
 
-module.exports = function finished(thingie, callback) {
-  var socket = thingie.socket || thingie
-  var res = thingie.res || thingie
+function onFinished(msg, listener) {
+  if (isFinished(msg) !== false) {
+    defer(listener)
+    return msg
+  }
 
-  if (res.finished || !socket.writable) {
-    defer(callback)
-    return thingie
+  // attach the listener to the message
+  attachListener(msg, listener)
+
+  return msg
+}
+
+/**
+ * Determine is message is already finished.
+ *
+ * @param {object} msg
+ * @return {boolean}
+ * @api public
+ */
+
+function isFinished(msg) {
+  var socket = msg.socket
+
+  if (typeof msg.finished === 'boolean') {
+    // OutgoingMessage
+    return Boolean(!socket || msg.finished || !socket.writable)
+  }
+
+  if (typeof msg.complete === 'boolean') {
+    // IncomingMessage
+    return Boolean(!socket || msg.complete || !socket.readable)
   }
 
-  var listener = res.__onFinished
+  // don't know
+  return undefined
+}
+
+/**
+ * Attach the listener to the message.
+ *
+ * @param {object} msg
+ * @return {function}
+ * @api private
+ */
+
+function attachListener(msg, listener) {
+  var attached = msg.__onFinished
+  var socket = msg.socket
 
   // create a private single listener with queue
-  if (!listener || !listener.queue) {
-    listener = res.__onFinished = function onFinished(err) {
-      if (res.__onFinished === listener) res.__onFinished = null
-      var queue = listener.queue || []
-      while (queue.length) queue.shift()(err)
-    }
-    listener.queue = []
+  if (!attached || !attached.queue) {
+    attached = msg.__onFinished = createListener(msg)
 
     // finished on first event
     first([
       [socket, 'error', 'close'],
-      [res, 'finish'],
-    ], listener)
+      [msg, 'end', 'finish'],
+    ], attached)
+  }
+
+  attached.queue.push(listener)
+}
+
+/**
+ * Create listener on message.
+ *
+ * @param {object} msg
+ * @return {function}
+ * @api private
+ */
+
+function createListener(msg) {
+  function listener(err) {
+    if (msg.__onFinished === listener) msg.__onFinished = null
+    if (!listener.queue) return
+
+    var queue = listener.queue
+    listener.queue = null
+
+    for (var i = 0; i < queue.length; i++) {
+      queue[i](err)
+    }
   }
 
-  listener.queue.push(callback)
+  listener.queue = []
 
-  return thingie
+  return listener
 }
diff --git a/package.json b/package.json
index ab0d433..0b1e5f3 100644
--- a/package.json
+++ b/package.json
@@ -1,24 +1,31 @@
 {
-  "name": "finished",
+  "name": "on-finished",
   "description": "Execute a callback when a request closes, finishes, or errors",
-  "version": "1.2.2",
-  "author": "Jonathan Ong <me at jongleberry.com> (http://jongleberry.com)",
+  "version": "2.1.0",
+  "contributors": [
+    "Douglas Christopher Wilson <doug at somethingdoug.com>",
+    "Jonathan Ong <me at jongleberry.com> (http://jongleberry.com)"
+  ],
   "license": "MIT",
-  "repository": "expressjs/finished",
+  "repository": "jshttp/on-finished",
   "dependencies": {
-    "ee-first": "1.0.3"
+    "ee-first": "1.0.5"
   },
   "devDependencies": {
-    "istanbul": "0.2.10",
-    "mocha": "~1.20.1",
-    "should": "~4.0.1"
+    "istanbul": "0.3.0",
+    "mocha": "~1.21.4"
   },
   "engine": {
     "node": ">= 0.8.0"
   },
+  "files": [
+    "HISTORY.md",
+    "LICENSE",
+    "index.js"
+  ],
   "scripts": {
-    "test": "mocha --reporter spec test/",
-    "test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot test/",
-    "test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec test/"
+    "test": "mocha --reporter spec --bail --check-leaks test/",
+    "test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot --check-leaks test/",
+    "test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec --check-leaks test/"
   }
 }
diff --git a/test/test.js b/test/test.js
index 61f794c..68bea38 100644
--- a/test/test.js
+++ b/test/test.js
@@ -1,90 +1,115 @@
 
-var EventEmitter = require('events').EventEmitter
-var should = require('should')
 var assert = require('assert')
 var http = require('http')
-
+var net = require('net')
 var onFinished = require('..')
 
-function createThingie() {
-  var ee = new EventEmitter
-  ee.socket = new EventEmitter
-  ee.socket.writable = true
-  return ee
-}
+describe('onFinished(res, listener)', function () {
+  it('should invoke listener given an unknwon object', function (done) {
+    onFinished({}, done)
+  })
 
-describe('on socket error', function () {
-  it('should execute the callback on socket error', function () {
-    var thingie = createThingie()
-    var called = false
-    onFinished(thingie, function (err) {
-      called = true
-      err.message.should.equal('boom')
+  describe('when the response finishes', function () {
+    it('should fire the callback', function (done) {
+      var server = http.createServer(function (req, res) {
+        onFinished(res, done)
+        setTimeout(res.end.bind(res), 0)
+      })
+
+      sendget(server)
     })
-    thingie.socket.emit('error', new Error('boom'))
-    called.should.be.true
-  })
 
-  it('should not execute the callback if response is finished', function (done) {
-    var thingie = createThingie()
-    onFinished(thingie, function (err) {
-      assert.ifError(err)
-      done()
+    it('should fire when called after finish', function (done) {
+      var server = http.createServer(function (req, res) {
+        onFinished(res, function () {
+          onFinished(res, done)
+        })
+        setTimeout(res.end.bind(res), 0)
+      })
+
+      sendget(server)
     })
-    thingie.emit('finish')
-    thingie.socket.emit(new Error('boom'))
   })
-})
 
-describe('when the socket is not writable', function () {
-  it('should execute the callback immediately', function (done) {
-    var thingie = createThingie()
-    thingie.socket.writable = false
-    onFinished(thingie, function (err) {
-      done()
+  describe('when using keep-alive', function () {
+    it('should fire for each response', function (done) {
+      var called = false
+      var server = http.createServer(function (req, res) {
+        onFinished(res, function () {
+          if (called) {
+            socket.end()
+            server.close()
+            done(called !== req ? null : new Error('fired twice on same req'))
+            return
+          }
+
+          called = req
+
+          writerequest(socket)
+        })
+
+        res.end()
+      })
+      var socket
+
+      server.listen(function () {
+        socket = net.connect(this.address().port, function () {
+          writerequest(this)
+        })
+      })
     })
   })
-})
 
-describe('when the socket closes', function () {
-  it('should execute the callback', function (done) {
-    var thingie = createThingie()
-    onFinished(thingie, done)
-    thingie.socket.emit('close')
-  })
-})
+  describe('when response errors', function () {
+    it('should fire with error', function (done) {
+      var server = http.createServer(function (req, res) {
+        onFinished(res, function (err) {
+          assert.ok(err)
+          done()
+        })
+
+        socket.on('error', noop)
+        socket.write('W')
+      })
+      var socket
 
-describe('when an emitter emits a non-error', function () {
-  it('should ignore the error', function (done) {
-    var thingie = createThingie()
-    onFinished(thingie, done)
-    thingie.socket.emit('close', false)
+      server.listen(function () {
+        socket = net.connect(this.address().port, function () {
+          writerequest(this, true)
+        })
+      })
+    })
   })
-})
 
-describe('http', function () {
-  describe('when the request finishes', function () {
+  describe('when the response aborts', function () {
     it('should execute the callback', function (done) {
+      var client
       var server = http.createServer(function (req, res) {
         onFinished(res, done)
-        setTimeout(res.end.bind(res), 0)
+        setTimeout(client.abort.bind(client), 0)
       })
       server.listen(function () {
         var port = this.address().port
-        http.get('http://127.0.0.1:' + port, function (res) {
-          res.resume()
-          res.on('close', server.close.bind(server))
-        })
+        client = http.get('http://127.0.0.1:' + port)
+        client.on('error', noop)
       })
     })
+  })
 
-    it('should execute the callback when called after finish', function (done) {
+  describe('when calling many times on same response', function () {
+    it('should not print warnings', function (done) {
       var server = http.createServer(function (req, res) {
-        onFinished(res, function () {
-          onFinished(res, done)
+        var stderr = captureStderr(function () {
+          for (var i = 0; i < 400; i++) {
+            onFinished(res, noop)
+          }
         })
-        setTimeout(res.end.bind(res), 0)
+
+        onFinished(res, done)
+        assert.equal(stderr, '')
+        res.end()
       })
+
       server.listen(function () {
         var port = this.address().port
         http.get('http://127.0.0.1:' + port, function (res) {
@@ -94,59 +119,320 @@ describe('http', function () {
       })
     })
   })
+})
 
-  describe('when the request aborts', function () {
-    it('should execute the callback', function (done) {
+describe('isFinished(res)', function () {
+  it('should return undefined for unknown object', function () {
+    assert.strictEqual(onFinished.isFinished({}), undefined)
+  })
+
+  it('should be false before response finishes', function (done) {
+    var server = http.createServer(function (req, res) {
+      assert.ok(!onFinished.isFinished(res))
+      res.end()
+      done()
+    })
+
+    sendget(server)
+  })
+
+  it('should be true after response finishes', function (done) {
+    var server = http.createServer(function (req, res) {
+      onFinished(res, function (err) {
+        assert.ifError(err)
+        assert.ok(onFinished.isFinished(res))
+        done()
+      })
+
+      res.end()
+    })
+
+    sendget(server)
+  })
+
+  describe('when response errors', function () {
+    it('should return true', function (done) {
+      var server = http.createServer(function (req, res) {
+        onFinished(res, function (err) {
+          assert.ok(err)
+          assert.ok(onFinished.isFinished(res))
+          done()
+        })
+
+        socket.on('error', noop)
+        socket.write('W')
+      })
+      var socket
+
+      server.listen(function () {
+        socket = net.connect(this.address().port, function () {
+          writerequest(this, true)
+        })
+      })
+    })
+  })
+
+  describe('when the response aborts', function () {
+    it('should return true', function (done) {
       var client
       var server = http.createServer(function (req, res) {
-        onFinished(res, done)
+        onFinished(res, function (err) {
+          assert.ifError(err)
+          assert.ok(onFinished.isFinished(res))
+          done()
+        })
         setTimeout(client.abort.bind(client), 0)
       })
       server.listen(function () {
         var port = this.address().port
         client = http.get('http://127.0.0.1:' + port)
-        client.on('error', function () {})
+        client.on('error', noop)
       })
     })
   })
 })
 
-describe('event emitter leaks', function () {
-  describe('when adding a lot of listeners on the same request', function () {
-    it('should not warn and add at most 1 listener per emitter per event', function () {
-      // we just have to make sure tests pass without a bunch of logs
-      var thingie = createThingie()
+describe('onFinished(req, listener)', function () {
+  describe('when the request finishes', function () {
+    it('should fire the callback', function (done) {
+      var server = http.createServer(function (req, res) {
+        onFinished(req, done)
+        req.resume()
+        setTimeout(res.end.bind(res), 0)
+      })
+
+      sendget(server)
+    })
+
+    it('should fire when called after finish', function (done) {
+      var server = http.createServer(function (req, res) {
+        onFinished(req, function () {
+          onFinished(req, done)
+        })
+        req.resume()
+        setTimeout(res.end.bind(res), 0)
+      })
+
+      sendget(server)
+    })
+  })
+
+  describe('when using keep-alive', function () {
+    it('should fire for each request', function (done) {
       var called = false
+      var server = http.createServer(function (req, res) {
+        var data = ''
+
+        onFinished(req, function (err) {
+          assert.ifError(err)
+          assert.equal(data, 'A')
+
+          if (called) {
+            socket.end()
+            server.close()
+            done(called !== req ? null : new Error('fired twice on same req'))
+            return
+          }
+
+          called = req
 
-      onFinished(thingie, function (err) {
-        called = true
-        err.message.should.equal('boom')
+          res.end()
+          writerequest(socket, true)
+        })
+
+        req.setEncoding('utf8')
+        req.on('data', function (str) {
+          data += str
+        })
+
+        socket.write('1\r\nA\r\n')
+        socket.write('0\r\n\r\n')
       })
+      var socket
 
-      for (var i = 0; i < 1000; i++) {
-        onFinished(thingie, noop)
-      }
+      server.listen(function () {
+        socket = net.connect(this.address().port, function () {
+          writerequest(this, true)
+        })
+      })
+    })
+  })
+
+  describe('when request errors', function () {
+    it('should fire with error', function (done) {
+      var server = http.createServer(function (req, res) {
+        onFinished(req, function (err) {
+          assert.ok(err)
+          done()
+        })
 
-      assert.equal(1, thingie.socket.listeners('error').length)
-      assert.equal(1, thingie.socket.listeners('close').length)
-      assert.equal(1, thingie.listeners('finish').length)
+        socket.on('error', noop)
+        socket.write('W')
+      })
+      var socket
+
+      server.listen(function () {
+        socket = net.connect(this.address().port, function () {
+          writerequest(this, true)
+        })
+      })
+    })
+  })
 
-      thingie.socket.emit('error', new Error('boom'))
-      called.should.be.true
+  describe('when the request aborts', function () {
+    it('should execute the callback', function (done) {
+      var client
+      var server = http.createServer(function (req, res) {
+        onFinished(req, done)
+        setTimeout(client.abort.bind(client), 0)
+      })
+      server.listen(function () {
+        var port = this.address().port
+        client = http.get('http://127.0.0.1:' + port)
+        client.on('error', noop)
+      })
     })
   })
 
-  it('should clean up after itself', function (done) {
-    var thingie = createThingie()
-    onFinished(thingie, function () {
-      assert(!thingie.socket.listeners('error').length)
-      assert(!thingie.socket.listeners('close').length)
-      assert(!thingie.listeners('finish').length)
+  describe('when calling many times on same request', function () {
+    it('should not print warnings', function (done) {
+      var server = http.createServer(function (req, res) {
+        var stderr = captureStderr(function () {
+          for (var i = 0; i < 400; i++) {
+            onFinished(req, noop)
+          }
+        })
+
+        onFinished(req, done)
+        assert.equal(stderr, '')
+        res.end()
+      })
+
+      server.listen(function () {
+        var port = this.address().port
+        http.get('http://127.0.0.1:' + port, function (res) {
+          res.resume()
+          res.on('close', server.close.bind(server))
+        })
+      })
+    })
+  })
+})
+
+describe('isFinished(req)', function () {
+  it('should invoke listener given an unknwon object', function (done) {
+    onFinished({}, done)
+  })
+
+  it('should return undefined for unknown object', function () {
+    assert.strictEqual(onFinished.isFinished({}), undefined)
+  })
+
+  it('should be false before request finishes', function (done) {
+    var server = http.createServer(function (req, res) {
+      assert.ok(!onFinished.isFinished(req))
+      req.resume()
+      res.end()
       done()
     })
 
-    thingie.socket.emit('error')
+    sendget(server)
+  })
+
+  it('should be true after request finishes', function (done) {
+    var server = http.createServer(function (req, res) {
+      onFinished(req, function (err) {
+        assert.ifError(err)
+        assert.ok(onFinished.isFinished(req))
+        done()
+      })
+
+      req.resume()
+      res.end()
+    })
+
+    sendget(server)
+  })
+
+  describe('when request errors', function () {
+    it('should return true', function (done) {
+      var server = http.createServer(function (req, res) {
+        onFinished(req, function (err) {
+          assert.ok(err)
+          assert.ok(onFinished.isFinished(req))
+          done()
+        })
+
+        socket.on('error', noop)
+        socket.write('W')
+      })
+      var socket
+
+      server.listen(function () {
+        socket = net.connect(this.address().port, function () {
+          writerequest(this, true)
+        })
+      })
+    })
+  })
+
+  describe('when the request aborts', function () {
+    it('should return true', function (done) {
+      var client
+      var server = http.createServer(function (req, res) {
+        onFinished(res, function (err) {
+          assert.ifError(err)
+          assert.ok(onFinished.isFinished(req))
+          done()
+        })
+        setTimeout(client.abort.bind(client), 0)
+      })
+      server.listen(function () {
+        var port = this.address().port
+        client = http.get('http://127.0.0.1:' + port)
+        client.on('error', noop)
+      })
+    })
   })
 })
 
+function captureStderr(fn) {
+  var chunks = []
+  var write = process.stderr.write
+
+  process.stderr.write = function write(chunk, encoding) {
+    chunks.push(new Buffer(chunk, encoding))
+  }
+
+  try {
+    fn()
+  } finally {
+    process.stderr.write = write
+  }
+
+  return Buffer.concat(chunks).toString('utf8')
+}
+
 function noop() {}
+
+function sendget(server) {
+  server.listen(function onListening() {
+    var port = this.address().port
+    http.get('http://127.0.0.1:' + port, function onResponse(res) {
+      res.resume()
+      res.on('close', server.close.bind(server))
+    })
+  })
+}
+
+function writerequest(socket, chunked) {
+  socket.write('GET / HTTP/1.1\r\n')
+  socket.write('Host: localhost\r\n')
+  socket.write('Connection: keep-alive\r\n')
+
+  if (chunked) {
+    socket.write('Transfer-Encoding: chunked\r\n')
+  }
+
+  socket.write('\r\n')
+}

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/node-finished.git



More information about the Pkg-javascript-commits mailing list