Skip to content

Commit 607915b

Browse files
committed
Add: fs option & tests. Closes pillarjs#160 Release 0.17.0
* Add: new option to specify which file system to use to serve files by default. * Add: exported erros for basic file system interface check * Add: basic tests via global injection
1 parent 09c2f2d commit 607915b

File tree

7 files changed

+127
-39
lines changed

7 files changed

+127
-39
lines changed

.travis.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ node_js:
88
- "3.3"
99
- "4.9"
1010
- "5.12"
11-
- "6.15"
11+
- "6.14"
1212
- "7.10"
13-
- "8.13"
13+
- "8.12"
1414
- "9.11"
1515
- "10.12"
1616
sudo: false

HISTORY.md

+7
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
unreleased
22
==========
33

4+
0.17.0 / 2018-02-07
5+
==========
6+
* Add `fs` option
7+
* test:
8+
- Add test.js for programmatic testing and debugging
9+
- Add `test:d` script command
10+
411
* deps: depd@~2.0.0
512
- Replace internal `eval` usage with `Function` constructor
613
- Use instance methods on `process` to check for listeners

README.md

+19-1
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,16 @@
66
[![Windows Build][appveyor-image]][appveyor-url]
77
[![Test Coverage][coveralls-image]][coveralls-url]
88

9+
> _This is a fork of an original [send](https://github.com/pillarjs/send) module. See changes made by this fork in [history file](./HISTORY.MD#0170--2018-02-07)._
10+
911
Send is a library for streaming files from the file system as a http response
1012
supporting partial responses (Ranges), conditional-GET negotiation (If-Match,
1113
If-Unmodified-Since, If-None-Match, If-Modified-Since), high test coverage,
1214
and granular events which may be leveraged to take appropriate actions in your
1315
application or framework.
1416

15-
Looking to serve up entire folders mapped to URLs? Try [serve-static](https://www.npmjs.org/package/serve-static).
17+
18+
Looking to serve up entire folders mapped to URLs? Try [serve-static (forked version)](/serve-static).
1619

1720
## Installation
1821

@@ -119,6 +122,15 @@ Serve files relative to `path`.
119122
Byte offset at which the stream starts, defaults to 0. The start is inclusive,
120123
meaning `start: 2` will include the 3rd byte in the stream.
121124

125+
##### fs
126+
127+
**Default**: [require('fs')](https://nodejs.org/api/fs.html)
128+
129+
File system to serve files by default.
130+
```js
131+
send(req, path, { fs: mockedFileSystem })
132+
```
133+
122134
#### Events
123135

124136
The `SendStream` is an event emitter and will emit the following events:
@@ -171,6 +183,12 @@ $ DEBUG=send node app
171183
$ npm install
172184
$ npm test
173185
```
186+
### Debugging tests
187+
In order to debug testing you can run programmatic mocha instance by command:
188+
```
189+
$ npm test:d
190+
```
191+
> _[package.json.scripts.test:d](./package.json)_
174192
175193
## Examples
176194

index.js

+20-5
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ var encodeUrl = require('encodeurl')
2020
var escapeHtml = require('escape-html')
2121
var etag = require('etag')
2222
var fresh = require('fresh')
23-
var fs = require('fs')
2423
var mime = require('mime')
2524
var ms = require('ms')
2625
var onFinished = require('on-finished')
@@ -84,6 +83,10 @@ function send (req, path, options) {
8483
return new SendStream(req, path, options)
8584
}
8685

86+
var errors = {}
87+
errors.INVALID_OPTION_FS_STAT = new TypeError('Invalid option: Incompatible file system interface: fs.stat() method is expected')
88+
errors.INVALID_OPTION_FS_CRTSTRM = new TypeError('Invalid option: Incompatible file system interface: fs.createReadStream() method is expected')
89+
send.errors = errors
8790
/**
8891
* Initialize a `SendStream` with the given `path`.
8992
*
@@ -102,6 +105,18 @@ function SendStream (req, path, options) {
102105
this.path = path
103106
this.req = req
104107

108+
// Dynamically import `fs` if not it is not provided by config
109+
this.fs = opts.fs || require('fs')
110+
111+
// Checking if provided "fs" is compatible
112+
if (typeof this.fs.stat !== 'function') {
113+
throw errors.INVALID_OPTION_FS_STAT
114+
}
115+
116+
if (typeof this.fs.createReadStream !== 'function') {
117+
throw errors.INVALID_OPTION_FS_CRTSTRM
118+
}
119+
105120
this._acceptRanges = opts.acceptRanges !== undefined
106121
? Boolean(opts.acceptRanges)
107122
: true
@@ -718,7 +733,7 @@ SendStream.prototype.sendFile = function sendFile (path) {
718733
var self = this
719734

720735
debug('stat "%s"', path)
721-
fs.stat(path, function onstat (err, stat) {
736+
this.fs.stat(path, function onstat (err, stat) {
722737
if (err && err.code === 'ENOENT' && !extname(path) && path[path.length - 1] !== sep) {
723738
// not found, check extensions
724739
return next(err)
@@ -739,7 +754,7 @@ SendStream.prototype.sendFile = function sendFile (path) {
739754
var p = path + '.' + self._extensions[i++]
740755

741756
debug('stat "%s"', p)
742-
fs.stat(p, function (err, stat) {
757+
self.fs.stat(p, function (err, stat) {
743758
if (err) return next(err)
744759
if (stat.isDirectory()) return next()
745760
self.emit('file', p, stat)
@@ -767,7 +782,7 @@ SendStream.prototype.sendIndex = function sendIndex (path) {
767782
var p = join(path, self._index[i])
768783

769784
debug('stat "%s"', p)
770-
fs.stat(p, function (err, stat) {
785+
self.fs.stat(p, function (err, stat) {
771786
if (err) return next(err)
772787
if (stat.isDirectory()) return next()
773788
self.emit('file', p, stat)
@@ -793,7 +808,7 @@ SendStream.prototype.stream = function stream (path, options) {
793808
var res = this.res
794809

795810
// pipe
796-
var stream = fs.createReadStream(path, options)
811+
var stream = this.fs.createReadStream(path, options)
797812
this.emit('stream', stream)
798813
stream.pipe(res)
799814

package.json

+33-31
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,48 @@
11
{
2-
"name": "send",
3-
"description": "Better streaming static file server with Range and conditional-GET support",
4-
"version": "0.16.2",
5-
"author": "TJ Holowaychuk <[email protected]>",
2+
"name" : "send",
3+
"description" : "Better streaming static file server with Range and conditional-GET support",
4+
"version" : "0.17.0",
5+
"author" : "TJ Holowaychuk <[email protected]>",
66
"contributors": [
77
"Douglas Christopher Wilson <[email protected]>",
88
"James Wyatt Cready <[email protected]>",
9-
"Jesús Leganés Combarro <[email protected]>"
9+
"Jesús Leganés Combarro <[email protected]>",
10+
"Davrononv Alexander Alisherovich <[email protected]>"
1011
],
11-
"license": "MIT",
12+
"license" : "MIT",
1213
"repository": "pillarjs/send",
13-
"keywords": [
14+
"keywords" : [
1415
"static",
1516
"file",
1617
"server"
1718
],
1819
"dependencies": {
19-
"debug": "2.6.9",
20-
"depd": "~2.0.0",
21-
"destroy": "~1.0.4",
22-
"encodeurl": "~1.0.2",
23-
"escape-html": "~1.0.3",
24-
"etag": "~1.8.1",
25-
"fresh": "0.5.2",
26-
"http-errors": "~1.7.1",
27-
"mime": "1.6.0",
28-
"ms": "2.1.1",
29-
"on-finished": "~2.3.0",
20+
"debug" : "2.6.9",
21+
"depd" : "~2.0.0",
22+
"destroy" : "~1.0.4",
23+
"encodeurl" : "~1.0.2",
24+
"escape-html" : "~1.0.3",
25+
"etag" : "~1.8.1",
26+
"fresh" : "0.5.2",
27+
"http-errors" : "~1.7.1",
28+
"mime" : "1.6.0",
29+
"ms" : "2.1.1",
30+
"on-finished" : "~2.3.0",
3031
"range-parser": "~1.2.0",
31-
"statuses": "~1.5.0"
32+
"statuses" : "~1.5.0"
3233
},
3334
"devDependencies": {
34-
"after": "0.8.2",
35-
"eslint": "5.8.0",
35+
"after" : "0.8.2",
36+
"eslint" : "5.8.0",
3637
"eslint-config-standard": "12.0.0",
37-
"eslint-plugin-import": "2.14.0",
38-
"eslint-plugin-markdown": "1.0.0-rc.1",
39-
"eslint-plugin-node": "7.0.1",
40-
"eslint-plugin-promise": "4.0.1",
38+
"eslint-plugin-import" : "2.14.0",
39+
"eslint-plugin-markdown": "1.0.0-beta.6",
40+
"eslint-plugin-node" : "7.0.1",
41+
"eslint-plugin-promise" : "4.0.1",
4142
"eslint-plugin-standard": "4.0.0",
42-
"istanbul": "0.4.5",
43-
"mocha": "5.2.0",
44-
"supertest": "3.3.0"
43+
"istanbul" : "0.4.5",
44+
"mocha" : "5.2.0",
45+
"supertest" : "3.3.0"
4546
},
4647
"files": [
4748
"HISTORY.md",
@@ -53,9 +54,10 @@
5354
"node": ">= 0.8.0"
5455
},
5556
"scripts": {
56-
"lint": "eslint --plugin markdown --ext js,md .",
57-
"test": "mocha --check-leaks --reporter spec --bail",
58-
"test-ci": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --check-leaks --reporter spec",
57+
"lint" : "eslint --plugin markdown --ext js,md .",
58+
"test" : "mocha --check-leaks --reporter spec --bail",
59+
"test:d" : "node --inspect-brk test.js",
60+
"test-ci" : "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --check-leaks --reporter spec",
5961
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --check-leaks --reporter dot"
6062
}
6163
}

test.js

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
var Mocha = require('mocha')
2+
var path = require('path')
3+
4+
// Instantiate a Mocha instance.
5+
var mocha = new Mocha()
6+
7+
var testDir = '/test/'
8+
mocha.addFile(
9+
path.join(__dirname, testDir, 'send.js')
10+
)
11+
// Run the tests.
12+
mocha.run(function (failures) {
13+
// exit with non-zero status if there were failures
14+
process.exitCode = failures ? 1 : 0
15+
})

test/send.js

+31
Original file line numberDiff line numberDiff line change
@@ -1418,6 +1418,37 @@ describe('send(file, options)', function () {
14181418
})
14191419
})
14201420
})
1421+
1422+
describe('fs', function () {
1423+
var FS_STAT = send.errors.INVALID_OPTION_FS_STAT
1424+
var CRTSTRM = send.errors.INVALID_OPTION_FS_CRTSTRM
1425+
it('must provide fs.stat()', function (done) {
1426+
try {
1427+
send(void 0, '', { fs: { createReadStream: function () {} } })
1428+
} catch (err) {
1429+
if (err === FS_STAT) {
1430+
done()
1431+
} else {
1432+
done(new Error('Must throw INVALID_OPTION_FS_STAT'))
1433+
}
1434+
return
1435+
}
1436+
done()
1437+
})
1438+
it('must implement fs.createReadStream()', function (done) {
1439+
try {
1440+
send(void 0, '', { fs: { stat: function () {} } })
1441+
} catch (err) {
1442+
if (err === CRTSTRM) {
1443+
done()
1444+
} else {
1445+
done(new Error('Must throw INVALID_OPTION_FS_CRTSTRM'))
1446+
}
1447+
return
1448+
}
1449+
done()
1450+
})
1451+
})
14211452
})
14221453

14231454
describe('send.mime', function () {

0 commit comments

Comments
 (0)