| @@ -0,0 +1,134 @@ | ||
| category: npm | ||
| title: Peer Dependencies | ||
| date: 2013-02-08T00:00:00Z | ||
| author: Domenic Denicola | ||
| slug: peer-dependencies | ||
|
|
||
| <i>Reposted from [Domenic's | ||
| blog](http://domenic.me/2013/02/08/peer-dependencies/) with | ||
| permission. Thanks!</i> | ||
|
|
||
| npm is awesome as a package manager. In particular, it handles sub-dependencies very well: if my package depends on | ||
| `request` version 2 and `some-other-library`, but `some-other-library` depends on `request` version 1, the resulting | ||
| dependency graph looks like: | ||
|
|
||
| ```text | ||
| ├── request@2.12.0 | ||
| └─┬ some-other-library@1.2.3 | ||
| └── request@1.9.9 | ||
| ``` | ||
|
|
||
| This is, generally, great: now `some-other-library` has its own copy of `request` v1 that it can use, while not | ||
| interfering with my package's v2 copy. Everyone's code works! | ||
|
|
||
| ## The Problem: Plugins | ||
|
|
||
| There's one use case where this falls down, however: *plugins*. A plugin package is meant to be used with another "host" | ||
| package, even though it does not always directly *use* the host package. There are many examples of this pattern in the | ||
| Node.js package ecosystem already: | ||
|
|
||
| - Grunt [plugins](http://gruntjs.com/#plugins-all) | ||
| - Chai [plugins](http://chaijs.com/plugins) | ||
| - Levelup [plugins](https://npmjs.org/package/level-hooks) | ||
| - Express [middleware](http://expressjs.com/api.html#middleware) | ||
| - Winston [transports](https://github.com/flatiron/winston/blob/master/docs/transports.md) | ||
|
|
||
| Even if you're not familiar with any of those use cases, surely you recall "jQuery plugins" from back when you were a | ||
| client-side developer: little `<script>`s you would drop into your page that would attach things to `jQuery.prototype` | ||
| for your later convenience. | ||
|
|
||
| In essence, plugins are designed to be used with host packages. But more importantly, they're designed to be used with | ||
| *particular versions* of host packages. For example, versions 1.x and 2.x of my `chai-as-promised` plugin work with | ||
| `chai` version 0.5, whereas versions 3.x work with `chai` 1.x. Or, in the faster-paced and less-semver–friendly world of | ||
| Grunt plugins, version 0.3.1 of `grunt-contrib-stylus` works with `grunt` 0.4.0rc4, but breaks when used with `grunt` | ||
| 0.4.0rc5 due to removed APIs. | ||
|
|
||
| As a package manager, a large part of npm's job when installing your dependencies is managing their versions. But its | ||
| usual model, with a `"dependencies"` hash in `package.json`, clearly falls down for plugins. Most plugins never actually | ||
| depend on their host package, i.e. grunt plugins never do `require("grunt")`, so even if plugins did put down their host | ||
| package as a dependency, the downloaded copy would never be used. So we'd be back to square one, with your application | ||
| possibly plugging in the plugin to a host package that it's incompatible with. | ||
|
|
||
| Even for plugins that do have such direct dependencies, probably due to the host package supplying utility APIs, | ||
| specifying the dependency in the plugin's `package.json` would result in a dependency tree with multiple copies of the | ||
| host package—not what you want. For example, let's pretend that `winston-mail` 0.2.3 specified `"winston": "0.5.x"` in | ||
| its `"dependencies"` hash, since that's the latest version it was tested against. As an app developer, you want the | ||
| latest and greatest stuff, so you look up the latest versions of `winston` and of `winston-mail`, putting them in your | ||
| `package.json` as | ||
|
|
||
| ```json | ||
| { | ||
| "dependencies": { | ||
| "winston": "0.6.2", | ||
| "winston-mail": "0.2.3" | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| But now, running `npm install` results in the unexpected dependency graph of | ||
|
|
||
| ```text | ||
| ├── winston@0.6.2 | ||
| └─┬ winston-mail@0.2.3 | ||
| └── winston@0.5.11 | ||
| ``` | ||
|
|
||
| I'll leave the subtle failures that come from the plugin using a different Winston API than the main application to | ||
| your imagination. | ||
|
|
||
| ## The Solution: Peer Dependencies | ||
|
|
||
| What we need is a way of expressing these "dependencies" between plugins and their host package. Some way of saying, "I | ||
| only work when plugged in to version 1.2.x of my host package, so if you install me, be sure that it's alongside a | ||
| compatible host." We call this relationship a *peer dependency*. | ||
|
|
||
| The peer dependency idea has been kicked around for [literally](https://github.com/isaacs/npm/issues/930) | ||
| [years](https://github.com/isaacs/npm/issues/1400). After | ||
| [volunteering](https://github.com/isaacs/npm/issues/1400#issuecomment-5932027) to get this done "over the weekend" nine | ||
| months ago, I finally found a free weekend, and now peer dependencies are in npm! | ||
|
|
||
| Specifically, they were introduced in a rudimentary form in npm 1.2.0, and refined over the next few releases into | ||
| something I'm actually happy with. Today Isaac packaged up npm 1.2.10 into | ||
| [Node.js 0.8.19](http://blog.nodejs.org/2013/02/06/node-v0-8-19-stable/), so if you've installed the latest version of | ||
| Node, you should be ready to use peer dependencies! | ||
|
|
||
| As proof, I present you the results of trying to install [`jitsu`](https://npmjs.org/package/jitsu) 0.11.6 with npm | ||
| 1.2.10: | ||
|
|
||
| ```text | ||
| npm ERR! peerinvalid The package flatiron does not satisfy its siblings' peerDependencies requirements! | ||
| npm ERR! peerinvalid Peer flatiron-cli-config@0.1.3 wants flatiron@~0.1.9 | ||
| npm ERR! peerinvalid Peer flatiron-cli-users@0.1.4 wants flatiron@~0.3.0 | ||
| ``` | ||
|
|
||
| As you can see, `jitsu` depends on two Flatiron-related packages, which themselves peer-depend on conflicting versions | ||
| of Flatiron. Good thing npm was around to help us figure out this conflict, so it could be fixed in version 0.11.7! | ||
|
|
||
| ## Using Peer Dependencies | ||
|
|
||
| Peer dependencies are pretty simple to use. When writing a plugin, figure out what version of the host package you | ||
| peer-depend on, and add it to your `package.json`: | ||
|
|
||
| ```json | ||
| { | ||
| "name": "chai-as-promised", | ||
| "peerDependencies": { | ||
| "chai": "1.x" | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| Now, when installing `chai-as-promised`, the `chai` package will come along with it. And if later you try to install | ||
| another Chai plugin that only works with 0.x versions of Chai, you'll get an error. Nice! | ||
|
|
||
| One piece of advice: peer dependency requirements, unlike those for regular dependencies, *should be lenient*. You | ||
| should not lock your peer dependencies down to specific patch versions. It would be really annoying if one Chai plugin | ||
| peer-depended on Chai 1.4.1, while another depended on Chai 1.5.0, simply because the authors were lazy and didn't spend | ||
| the time figuring out the actual minimum version of Chai they are compatible with. | ||
|
|
||
| The best way to determine what your peer dependency requirements should be is to actually follow | ||
| [semver](http://semver.org/). Assume that only changes in the host package's major version will break your plugin. Thus, | ||
| if you've worked with every 1.x version of the host package, use `"~1.0"` or `"1.x"` to express this. If you depend on | ||
| features introduced in 1.5.2, use `">= 1.5.2 < 2"`. | ||
|
|
||
| Now go forth, and peer depend! |
| @@ -0,0 +1,62 @@ | ||
| title: Node v0.8.20 (Stable) | ||
| slug: node-v0-8-20-stable | ||
| category: release | ||
| date: Fri Feb 15 11:21:42 PST 2013 | ||
| version: 0.8.20 | ||
|
|
||
| 2013.02.15, Version 0.8.20 (Stable) | ||
|
|
||
| * npm: Upgrade to v1.2.11 | ||
|
|
||
| * http: Do not let Agent hand out destroyed sockets (isaacs) | ||
|
|
||
| * http: Raise hangup error on destroyed socket write (isaacs) | ||
|
|
||
| * http: protect against response splitting attacks (Bert Belder) | ||
|
|
||
|
|
||
| Source Code: http://nodejs.org/dist/v0.8.20/node-v0.8.20.tar.gz | ||
|
|
||
| Macintosh Installer (Universal): http://nodejs.org/dist/v0.8.20/node-v0.8.20.pkg | ||
|
|
||
| Windows Installer: http://nodejs.org/dist/v0.8.20/node-v0.8.20-x86.msi | ||
|
|
||
| Windows x64 Installer: http://nodejs.org/dist/v0.8.20/x64/node-v0.8.20-x64.msi | ||
|
|
||
| Windows x64 Files: http://nodejs.org/dist/v0.8.20/x64/ | ||
|
|
||
| Linux 32-bit Binary: http://nodejs.org/dist/v0.8.20/node-v0.8.20-linux-x86.tar.gz | ||
|
|
||
| Linux 64-bit Binary: http://nodejs.org/dist/v0.8.20/node-v0.8.20-linux-x64.tar.gz | ||
|
|
||
| Solaris 32-bit Binary: http://nodejs.org/dist/v0.8.20/node-v0.8.20-sunos-x86.tar.gz | ||
|
|
||
| Solaris 64-bit Binary: http://nodejs.org/dist/v0.8.20/node-v0.8.20-sunos-x64.tar.gz | ||
|
|
||
| Other release files: http://nodejs.org/dist/v0.8.20/ | ||
|
|
||
| Website: http://nodejs.org/docs/v0.8.20/ | ||
|
|
||
| Documentation: http://nodejs.org/docs/v0.8.20/api/ | ||
|
|
||
| Shasums: | ||
| ``` | ||
| 2b87bf077022b8fa1cbcec10ea3866574fed2b75 node-v0.8.20-darwin-x64.tar.gz | ||
| 42023ffbdbf36ef69250bd750f112e684eb97008 node-v0.8.20-darwin-x86.tar.gz | ||
| 93480cbc67f2c757879228434bce1fd765db7df8 node-v0.8.20-linux-x64.tar.gz | ||
| 7fedae5ce4b366d5dcaa7f2e770b3ff739648a51 node-v0.8.20-linux-x86.tar.gz | ||
| fd66ea1bfbe5c8fe8df5ba8cc79cd3fab6e753ac node-v0.8.20-sunos-x64.tar.gz | ||
| ca6ad9aa92330358f6201191347451ab42fe12cf node-v0.8.20-sunos-x86.tar.gz | ||
| 200ff5e5083df2a6bb4552e673d81b498e9812f0 node-v0.8.20-x86.msi | ||
| 54440b1f525da0126b434440ee6433c2b96959ae node-v0.8.20.pkg | ||
| b780f58f0e3bc43d2380d4a935f2b45350783b37 node-v0.8.20.tar.gz | ||
| 8e13b125c3572a1cb46364b3241405cdf7af1a82 node.exe | ||
| f67ea64d6686207dbacb9bb8feacce3ac8899ec8 node.exp | ||
| c338212caf48d945e8e8049c2a0c30e38e8730d6 node.lib | ||
| 019b24c60cdb03f9d8209290e7af90e8565999e7 node.pdb | ||
| 67fff498c5271033073a3ca9fc01178b5f5c309a x64/node-v0.8.20-x64.msi | ||
| 6ecab177a47ff5c74397799b329c2359b40c7d1f x64/node.exe | ||
| bcd51345c05a28be5db3553fc578aa3dd52fc97e x64/node.exp | ||
| 825f2ba0bb9d7bd170adef89009b84ee147754e5 x64/node.lib | ||
| 50c4cc483cc4b675966c7ec524afacb59ff99164 x64/node.pdb | ||
| ``` |
| @@ -0,0 +1,78 @@ | ||
| date: Thu Feb 7 10:32:17 PST 2013 | ||
| title: Node v0.9.9 (Unstable) | ||
| version: 0.9.9 | ||
| category: release | ||
| slug: node-v0-9-9-unstable | ||
|
|
||
| 2013.02.07, Version 0.9.9 (Unstable) | ||
|
|
||
| * tls: port CryptoStream to streams2 (Fedor Indutny) | ||
|
|
||
| * typed arrays: only share ArrayBuffer backing store (Ben Noordhuis) | ||
|
|
||
| * stream: make Writable#end() accept a callback function (Nathan Rajlich) | ||
|
|
||
| * buffer: optimize 'hex' handling (Ben Noordhuis) | ||
|
|
||
| * dns, cares: don't filter NOTIMP, REFUSED, SERVFAIL (Ben Noordhuis) | ||
|
|
||
| * readline: treat bare \r as a line ending (isaacs) | ||
|
|
||
| * readline: make \r\n emit one 'line' event (Ben Noordhuis) | ||
|
|
||
| * cluster: support datagram sockets (Bert Belder) | ||
|
|
||
| * stream: Correct Transform class backpressure (isaacs) | ||
|
|
||
| * addon: Pass module object to NODE_MODULE init function (isaacs, Rod Vagg) | ||
|
|
||
| * buffer: slow buffer copy compatibility fix (Trevor Norris) | ||
|
|
||
| * Add bytesWritten to tls.CryptoStream (Andy Burke) | ||
|
|
||
|
|
||
| Source Code: http://nodejs.org/dist/v0.9.9/node-v0.9.9.tar.gz | ||
|
|
||
| Macintosh Installer (Universal): http://nodejs.org/dist/v0.9.9/node-v0.9.9.pkg | ||
|
|
||
| Windows Installer: http://nodejs.org/dist/v0.9.9/node-v0.9.9-x86.msi | ||
|
|
||
| Windows x64 Installer: http://nodejs.org/dist/v0.9.9/x64/node-v0.9.9-x64.msi | ||
|
|
||
| Windows x64 Files: http://nodejs.org/dist/v0.9.9/x64/ | ||
|
|
||
| Linux 32-bit Binary: http://nodejs.org/dist/v0.9.9/node-v0.9.9-linux-x86.tar.gz | ||
|
|
||
| Linux 64-bit Binary: http://nodejs.org/dist/v0.9.9/node-v0.9.9-linux-x64.tar.gz | ||
|
|
||
| Solaris 32-bit Binary: http://nodejs.org/dist/v0.9.9/node-v0.9.9-sunos-x86.tar.gz | ||
|
|
||
| Solaris 64-bit Binary: http://nodejs.org/dist/v0.9.9/node-v0.9.9-sunos-x64.tar.gz | ||
|
|
||
| Other release files: http://nodejs.org/dist/v0.9.9/ | ||
|
|
||
| Website: http://nodejs.org/docs/v0.9.9/ | ||
|
|
||
| Documentation: http://nodejs.org/docs/v0.9.9/api/ | ||
|
|
||
| Shasums: | ||
| ``` | ||
| 643c26c2fc0c9ddeee99d346af86a022e6b470bc node-v0.9.9-darwin-x64.tar.gz | ||
| f3ffeb08ceab15fd24a33c8d1974be952177b623 node-v0.9.9-darwin-x86.tar.gz | ||
| 63d6ce5e4333a0cd203753a3153998076baa23a7 node-v0.9.9-linux-x64.tar.gz | ||
| f1008b823b6010bd3ed3fd4f422eac3af5bd61da node-v0.9.9-linux-x86.tar.gz | ||
| 679b09328f1a0c3225286a891bb5b4de131777d6 node-v0.9.9-sunos-x64.tar.gz | ||
| 4253f2e976a05ee6ea6ecc3b583e942b812d0b86 node-v0.9.9-sunos-x86.tar.gz | ||
| 0436ee0e57d12d5fc53914f9157521427d016629 node-v0.9.9-x86.msi | ||
| 8a98bc39e9c99a1a1dad6f38a47f56eeb9ad6ecd node-v0.9.9.pkg | ||
| af1deb80c79f256b319a727f8593740ff99cdbc8 node-v0.9.9.tar.gz | ||
| ab3db4d6ffab88bb1babdddd96ca8d2c6caf4625 node.exe | ||
| 56f5a3c72992463435f6649b31da81fd679e91ae node.exp | ||
| e77f0097ce66317fc255b8e1642eaa675c190267 node.lib | ||
| 5ff7b6d7f1001383b4bd97e1315c67e7b223477d node.pdb | ||
| 5b4dcf545eace51a4cae58e9c42b73604f6eb0f9 x64/node-v0.9.9-x64.msi | ||
| 43fd59cf0df5bdf21690a43a68a8f16160e28ec6 x64/node.exe | ||
| b4845d2318dd5b1030eeca02703d7f19ebf2ef15 x64/node.exp | ||
| 2726441e5ff354bc51a841fa9a5a193d39831ac0 x64/node.lib | ||
| df9083c37cf13109326df30df01e9692238ac381 x64/node.pdb | ||
| ``` |
| @@ -0,0 +1,106 @@ | ||
| // Copyright Joyent, Inc. and other Node contributors. | ||
| // | ||
| // 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. | ||
|
|
||
| var common = require('../common'); | ||
| var assert = require('assert'); | ||
| var http = require('http'); | ||
|
|
||
| var server = http.createServer(function(req, res) { | ||
| res.writeHead(200, {'Content-Type': 'text/plain'}); | ||
| res.end('Hello World\n'); | ||
| }).listen(common.PORT); | ||
|
|
||
| var agent = new http.Agent({maxSockets: 1}); | ||
|
|
||
| agent.on('free', function(socket, host, port) { | ||
| console.log('freeing socket. destroyed? ', socket.destroyed); | ||
| }); | ||
|
|
||
| var requestOptions = { | ||
| agent: agent, | ||
| host: 'localhost', | ||
| port: common.PORT, | ||
| path: '/' | ||
| }; | ||
|
|
||
| var request1 = http.get(requestOptions, function(response) { | ||
| // assert request2 is queued in the agent | ||
| var key = 'localhost:' + common.PORT; | ||
| assert(agent.requests[key].length === 1); | ||
| console.log('got response1'); | ||
| request1.socket.on('close', function() { | ||
| console.log('request1 socket closed'); | ||
| }); | ||
| response.pipe(process.stdout); | ||
| response.on('end', function() { | ||
| console.log('response1 done'); | ||
| ///////////////////////////////// | ||
| // | ||
| // THE IMPORTANT PART | ||
| // | ||
| // It is possible for the socket to get destroyed and other work | ||
| // to run before the 'close' event fires because it happens on | ||
| // nextTick. This example is contrived because it destroys the | ||
| // socket manually at just the right time, but at Voxer we have | ||
| // seen cases where the socket is destroyed by non-user code | ||
| // then handed out again by an agent *before* the 'close' event | ||
| // is triggered. | ||
| request1.socket.destroy(); | ||
|
|
||
| process.nextTick(function() { | ||
| // assert request2 was removed from the queue | ||
| assert(!agent.requests[key]); | ||
| console.log("waiting for request2.onSocket's nextTick"); | ||
| process.nextTick(function() { | ||
| // assert that the same socket was not assigned to request2, | ||
| // since it was destroyed. | ||
| assert(request1.socket !== request2.socket); | ||
| assert(!request2.socket.destroyed, 'the socket is destroyed'); | ||
| }); | ||
| }); | ||
| }); | ||
| }); | ||
|
|
||
| var request2 = http.get(requestOptions, function(response) { | ||
| assert(!request2.socket.destroyed); | ||
| assert(request1.socket.destroyed); | ||
| // assert not reusing the same socket, since it was destroyed. | ||
| assert(request1.socket !== request2.socket); | ||
| console.log('got response2'); | ||
| var gotClose = false; | ||
| var gotResponseEnd = false; | ||
| request2.socket.on('close', function() { | ||
| console.log('request2 socket closed'); | ||
| gotClose = true; | ||
| done(); | ||
| }); | ||
| response.pipe(process.stdout); | ||
| response.on('end', function() { | ||
| console.log('response2 done'); | ||
| gotResponseEnd = true; | ||
| done(); | ||
| }); | ||
|
|
||
| function done() { | ||
| if (gotResponseEnd && gotClose) | ||
| server.close(); | ||
| } | ||
| }); |
| @@ -0,0 +1,131 @@ | ||
| // Copyright Joyent, Inc. and other Node contributors. | ||
| // | ||
| // 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. | ||
|
|
||
| var common = require('../common'); | ||
| var assert = require('assert'); | ||
|
|
||
| // Fix the memory explosion that happens when writing to a http request | ||
| // where the server has destroyed the socket on us between a successful | ||
| // first request, and a subsequent request that reuses the socket. | ||
| // | ||
| // This test should not be ported to v0.10 and higher, because the | ||
| // problem is fixed by not ignoring ECONNRESET in the first place. | ||
|
|
||
| var http = require('http'); | ||
| var net = require('net'); | ||
| var server = http.createServer(function(req, res) { | ||
| // simulate a server that is in the process of crashing or something | ||
| // it only crashes after the first request, but before the second, | ||
| // which reuses the connection. | ||
| res.end('hallo wereld\n', function() { | ||
| setTimeout(function() { | ||
| req.connection.destroy(); | ||
| }, 100); | ||
| }); | ||
| }); | ||
|
|
||
| var gotFirstResponse = false; | ||
| var gotFirstData = false; | ||
| var gotFirstEnd = false; | ||
| server.listen(common.PORT, function() { | ||
|
|
||
| var gotFirstResponse = false; | ||
| var first = http.request({ | ||
| port: common.PORT, | ||
| path: '/' | ||
| }); | ||
| first.on('response', function(res) { | ||
| gotFirstResponse = true; | ||
| res.on('data', function(chunk) { | ||
| gotFirstData = true; | ||
| }); | ||
| res.on('end', function() { | ||
| gotFirstEnd = true; | ||
| }) | ||
| }); | ||
| first.end(); | ||
| second(); | ||
|
|
||
| function second() { | ||
| var sec = http.request({ | ||
| port: common.PORT, | ||
| path: '/', | ||
| method: 'POST' | ||
| }); | ||
|
|
||
| var timer = setTimeout(write, 200); | ||
| var writes = 0; | ||
| var sawFalseWrite; | ||
|
|
||
| var gotError = false; | ||
| sec.on('error', function(er) { | ||
| assert.equal(gotError, false); | ||
| gotError = true; | ||
| assert(er.code === 'ECONNRESET'); | ||
| clearTimeout(timer); | ||
| test(); | ||
| }); | ||
|
|
||
| function write() { | ||
| if (++writes === 64) { | ||
| clearTimeout(timer); | ||
| sec.end(); | ||
| test(); | ||
| } else { | ||
| timer = setTimeout(write); | ||
| var writeRet = sec.write(new Buffer('hello')); | ||
|
|
||
| // Once we find out that the connection is destroyed, every | ||
| // write() returns false | ||
| if (sawFalseWrite) | ||
| assert.equal(writeRet, false); | ||
| else | ||
| sawFalseWrite = writeRet === false; | ||
| } | ||
| } | ||
|
|
||
| assert.equal(first.connection, sec.connection, | ||
| 'should reuse connection'); | ||
|
|
||
| sec.on('response', function(res) { | ||
| res.on('data', function(chunk) { | ||
| console.error('second saw data: ' + chunk); | ||
| }); | ||
| res.on('end', function() { | ||
| console.error('second saw end'); | ||
| }); | ||
| }); | ||
|
|
||
| function test() { | ||
| server.close(); | ||
| assert(sec.connection.destroyed); | ||
| if (sec.output.length || sec.outputEncodings.length) | ||
| console.error('bad happened', sec.output, sec.outputEncodings); | ||
| assert.equal(sec.output.length, 0); | ||
| assert.equal(sec.outputEncodings, 0); | ||
| assert(gotError); | ||
| assert(gotFirstResponse); | ||
| assert(gotFirstData); | ||
| assert(gotFirstEnd); | ||
| console.log('ok'); | ||
| } | ||
| } | ||
| }); |