This commit is contained in:
Dawid Dziurla 2020-03-26 15:37:35 +01:00
parent d9becc67b6
commit 9308795b8b
No known key found for this signature in database
GPG key ID: 7B6D8368172E9B0B
964 changed files with 104265 additions and 16 deletions

9
node_modules/sonic-boom/.travis.yml generated vendored Normal file
View file

@ -0,0 +1,9 @@
language: node_js
sudo: false
node_js:
- '6'
- '8'
- '10'
- '11'
- '12'
- '13'

21
node_modules/sonic-boom/LICENSE generated vendored Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2017 Matteo Collina
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.

100
node_modules/sonic-boom/README.md generated vendored Normal file
View file

@ -0,0 +1,100 @@
# sonic-boom  [![Build Status](https://travis-ci.org/mcollina/sonic-boom.svg?branch=master)](https://travis-ci.org/mcollina/sonic-boom)
Extremely fast utf8-only stream implementation to write to files and
file descriptors.
This implementation is partial, but support backpressure and `.pipe()` in is here.
However, it is 2-3x faster than Node Core `fs.createWriteStream()`:
```
benchSonic*1000: 2215.220ms
benchSonicSync*1000: 8315.173ms
benchSonic4k*1000: 2184.558ms
benchSonicSync4k*1000: 1733.582ms
benchCore*1000: 6513.752ms
```
Note that sync mode without buffering is _slower_ than a Node Core WritableStream, however
this mode matches the expected behavior of `console.log()`.
Note that if this is used to log to a windows terminal (`cmd.exe` or
powershell), it is needed to run `chcp 65001` in the terminal to
correctly display utf-8 characters, see
[chcp](https://ss64.com/nt/chcp.html) for more details.
## Install
```
npm i sonic-boom
```
## Example
```js
'use strict'
const SonicBoom = require('sonic-boom')
const sonic = new SonicBoom(process.stdout.fd) // or '/path/to/destination'
for (var i = 0; i < 10; i++) {
sonic.write('hello sonic\n')
}
```
## API
### SonicBoom(String|Number, [minLength], [sync])
Creates a new instance of SonicBoom.
The first argument can be:
1. a string that is a path to a file to be written to (mode `'a'`)
2. a file descriptor, something that is returned by `fs.open` or
`fs.openSync`.
The second argument is the minimum length of the internal buffer that is
required before flushing.
The third argument is a flag that, when true, causes `SonicBoom` to perform synchronous writes.
It will emit the `'ready'` event when a file descriptor is available.
### SonicBoom#write(string)
Writes the string to the file.
It will return false to signal the producer to slow down.
### SonicBoom#flush()
Writes the current buffer to the file if a write was not in progress.
Do nothing if `minLength` is zero or if it is already writing.
### SonicBoom#reopen([file])
Reopen the file in place, useful for log rotation.
Example:
```js
const stream = new SonicBoom('./my.log')
process.on('SIGUSR2', function () {
stream.reopen()
})
```
### SonicBoom#flushSync()
Flushes the buffered data synchronously. This is a costly operation.
### SonicBoom#end()
Closes the stream, the data will be flushed down asynchronously
### SonicBook#destroy()
Closes the stream immediately, the data is not flushed.
## License
MIT

63
node_modules/sonic-boom/bench.js generated vendored Normal file
View file

@ -0,0 +1,63 @@
'use strict'
var bench = require('fastbench')
var SonicBoom = require('./')
var fs = require('fs')
var core = fs.createWriteStream('/dev/null')
var fd = fs.openSync('/dev/null', 'w')
var sonic = new SonicBoom(fd)
var sonic4k = new SonicBoom(fd, 4096)
var sonicSync = new SonicBoom(fd, 0, true)
var sonicSync4k = new SonicBoom(fd, 4096, true)
var MAX = 10000
function str () {
var res = ''
for (var i = 0; i < 10; i++) {
res += 'hello'
}
return res
}
setTimeout(doBench, 100)
var run = bench([
function benchSonic (cb) {
sonic.once('drain', cb)
for (var i = 0; i < MAX; i++) {
sonic.write(str())
}
},
function benchSonicSync (cb) {
sonicSync.once('drain', cb)
for (var i = 0; i < MAX; i++) {
sonicSync.write(str())
}
},
function benchSonic4k (cb) {
sonic4k.once('drain', cb)
for (var i = 0; i < MAX; i++) {
sonic4k.write(str())
}
},
function benchSonicSync4k (cb) {
sonicSync4k.once('drain', cb)
for (var i = 0; i < MAX; i++) {
sonicSync4k.write(str())
}
},
function benchCore (cb) {
core.once('drain', cb)
for (var i = 0; i < MAX; i++) {
core.write(str())
}
}
], 1000)
function doBench () {
run(run)
}

18
node_modules/sonic-boom/check.js generated vendored Normal file
View file

@ -0,0 +1,18 @@
'use strict'
const SonicBoom = require('.')
const sonic = new SonicBoom(process.stdout.fd)
let count = 0
function scheduleWrites () {
for (var i = 0; i < 1000; i++) {
sonic.write('hello sonic\n')
console.log('hello console')
}
if (++count < 10) {
setTimeout(scheduleWrites, 100)
}
}
scheduleWrites()

8
node_modules/sonic-boom/example.js generated vendored Normal file
View file

@ -0,0 +1,8 @@
'use strict'
const SonicBoom = require('.')
const sonic = new SonicBoom(process.stdout.fd) // or 'destination'
for (var i = 0; i < 10; i++) {
sonic.write('hello sonic\n')
}

22
node_modules/sonic-boom/fixtures/firehose.js generated vendored Normal file
View file

@ -0,0 +1,22 @@
'use strict'
const SonicBoom = require('..')
const out = new SonicBoom(process.stdout.fd)
const str = Buffer.alloc(1000).fill('a').toString()
let i = 0
function write () {
if (i++ === 10) {
return
}
if (out.write(str)) {
write()
} else {
out.once('drain', write)
}
}
write()

317
node_modules/sonic-boom/index.js generated vendored Normal file
View file

@ -0,0 +1,317 @@
'use strict'
const fs = require('fs')
const EventEmitter = require('events')
const flatstr = require('flatstr')
const inherits = require('util').inherits
const BUSY_WRITE_TIMEOUT = 100
const sleep = require('atomic-sleep')
// 16 MB - magic number
// This constant ensures that SonicBoom only needs
// 32 MB of free memory to run. In case of having 1GB+
// of data to write, this prevents an out of memory
// condition.
const MAX_WRITE = 16 * 1024 * 1024
function openFile (file, sonic) {
sonic._opening = true
sonic._writing = true
sonic.file = file
fs.open(file, 'a', (err, fd) => {
if (err) {
sonic.emit('error', err)
return
}
sonic.fd = fd
sonic._reopening = false
sonic._opening = false
sonic._writing = false
sonic.emit('ready')
if (sonic._reopening) {
return
}
// start
var len = sonic._buf.length
if (len > 0 && len > sonic.minLength && !sonic.destroyed) {
actualWrite(sonic)
}
})
}
function SonicBoom (fd, minLength, sync) {
if (!(this instanceof SonicBoom)) {
return new SonicBoom(fd, minLength, sync)
}
this._buf = ''
this.fd = -1
this._writing = false
this._writingBuf = ''
this._ending = false
this._reopening = false
this._asyncDrainScheduled = false
this.file = null
this.destroyed = false
this.sync = sync || false
this.minLength = minLength || 0
if (typeof fd === 'number') {
this.fd = fd
process.nextTick(() => this.emit('ready'))
} else if (typeof fd === 'string') {
openFile(fd, this)
} else {
throw new Error('SonicBoom supports only file descriptors and files')
}
this.release = (err, n) => {
if (err) {
if (err.code === 'EAGAIN') {
if (this.sync) {
// This error code should not happen in sync mode, because it is
// not using the underlining operating system asynchronous functions.
// However it happens, and so we handle it.
// Ref: https://github.com/pinojs/pino/issues/783
try {
sleep(BUSY_WRITE_TIMEOUT)
this.release(undefined, 0)
} catch (err) {
this.release(err)
}
} else {
// Let's give the destination some time to process the chunk.
setTimeout(() => {
fs.write(this.fd, this._writingBuf, 'utf8', this.release)
}, BUSY_WRITE_TIMEOUT)
}
} else {
this.emit('error', err)
}
return
}
if (this._writingBuf.length !== n) {
this._writingBuf = this._writingBuf.slice(n)
if (this.sync) {
try {
do {
n = fs.writeSync(this.fd, this._writingBuf, 'utf8')
this._writingBuf = this._writingBuf.slice(n)
} while (this._writingBuf.length !== 0)
} catch (err) {
this.release(err)
return
}
} else {
fs.write(this.fd, this._writingBuf, 'utf8', this.release)
return
}
}
this._writingBuf = ''
if (this.destroyed) {
return
}
var len = this._buf.length
if (this._reopening) {
this._writing = false
this._reopening = false
this.reopen()
} else if (len > 0 && len > this.minLength) {
actualWrite(this)
} else if (this._ending) {
if (len > 0) {
actualWrite(this)
} else {
this._writing = false
actualClose(this)
}
} else {
this._writing = false
if (this.sync) {
if (!this._asyncDrainScheduled) {
this._asyncDrainScheduled = true
process.nextTick(emitDrain, this)
}
} else {
this.emit('drain')
}
}
}
}
function emitDrain (sonic) {
sonic._asyncDrainScheduled = false
sonic.emit('drain')
}
inherits(SonicBoom, EventEmitter)
SonicBoom.prototype.write = function (data) {
if (this.destroyed) {
throw new Error('SonicBoom destroyed')
}
this._buf += data
var len = this._buf.length
if (!this._writing && len > this.minLength) {
actualWrite(this)
}
return len < 16384
}
SonicBoom.prototype.flush = function () {
if (this.destroyed) {
throw new Error('SonicBoom destroyed')
}
if (this._writing || this.minLength <= 0) {
return
}
actualWrite(this)
}
SonicBoom.prototype.reopen = function (file) {
if (this.destroyed) {
throw new Error('SonicBoom destroyed')
}
if (this._opening) {
this.once('ready', () => {
this.reopen(file)
})
return
}
if (this._ending) {
return
}
if (!this.file) {
throw new Error('Unable to reopen a file descriptor, you must pass a file to SonicBoom')
}
this._reopening = true
if (this._writing) {
return
}
fs.close(this.fd, (err) => {
if (err) {
return this.emit('error', err)
}
})
openFile(file || this.file, this)
}
SonicBoom.prototype.end = function () {
if (this.destroyed) {
throw new Error('SonicBoom destroyed')
}
if (this._opening) {
this.once('ready', () => {
this.end()
})
return
}
if (this._ending) {
return
}
this._ending = true
if (!this._writing && this._buf.length > 0 && this.fd >= 0) {
actualWrite(this)
return
}
if (this._writing) {
return
}
actualClose(this)
}
SonicBoom.prototype.flushSync = function () {
if (this.destroyed) {
throw new Error('SonicBoom destroyed')
}
if (this.fd < 0) {
throw new Error('sonic boom is not ready yet')
}
if (this._buf.length > 0) {
fs.writeSync(this.fd, this._buf, 'utf8')
this._buf = ''
}
}
SonicBoom.prototype.destroy = function () {
if (this.destroyed) {
return
}
actualClose(this)
}
function actualWrite (sonic) {
sonic._writing = true
var buf = sonic._buf
var release = sonic.release
if (buf.length > MAX_WRITE) {
buf = buf.slice(0, MAX_WRITE)
sonic._buf = sonic._buf.slice(MAX_WRITE)
} else {
sonic._buf = ''
}
flatstr(buf)
sonic._writingBuf = buf
if (sonic.sync) {
try {
var written = fs.writeSync(sonic.fd, buf, 'utf8')
release(null, written)
} catch (err) {
release(err)
}
} else {
fs.write(sonic.fd, buf, 'utf8', release)
}
}
function actualClose (sonic) {
if (sonic.fd === -1) {
sonic.once('ready', actualClose.bind(null, sonic))
return
}
// TODO write a test to check if we are not leaking fds
fs.close(sonic.fd, (err) => {
if (err) {
sonic.emit('error', err)
return
}
if (sonic._ending && !sonic._writing) {
sonic.emit('finish')
}
sonic.emit('close')
})
sonic.destroyed = true
sonic._buf = ''
}
module.exports = SonicBoom

67
node_modules/sonic-boom/package.json generated vendored Normal file
View file

@ -0,0 +1,67 @@
{
"_from": "sonic-boom@^0.7.5",
"_id": "sonic-boom@0.7.7",
"_inBundle": false,
"_integrity": "sha512-Ei5YOo5J64GKClHIL/5evJPgASXFVpfVYbJV9PILZQytTK6/LCwHvsZJW2Ig4p9FMC2OrBrMnXKgRN/OEoAWfg==",
"_location": "/sonic-boom",
"_phantomChildren": {},
"_requested": {
"type": "range",
"registry": true,
"raw": "sonic-boom@^0.7.5",
"name": "sonic-boom",
"escapedName": "sonic-boom",
"rawSpec": "^0.7.5",
"saveSpec": null,
"fetchSpec": "^0.7.5"
},
"_requiredBy": [
"/pino"
],
"_resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-0.7.7.tgz",
"_shasum": "d921de887428208bfa07b0ae32c278de043f350a",
"_spec": "sonic-boom@^0.7.5",
"_where": "/home/dawidd6/github/dawidd6/action-debian-package/node_modules/pino",
"author": {
"name": "Matteo Collina",
"email": "hello@matteocollina.com"
},
"bugs": {
"url": "https://github.com/mcollina/sonic-boom/issues"
},
"bundleDependencies": false,
"dependencies": {
"atomic-sleep": "^1.0.0",
"flatstr": "^1.0.12"
},
"deprecated": false,
"description": "Extremely fast utf8 only stream implementation",
"devDependencies": {
"fastbench": "^1.0.1",
"pre-commit": "^1.2.2",
"proxyquire": "^2.1.0",
"standard": "^13.0.2",
"tap": "^12.1.0"
},
"homepage": "https://github.com/mcollina/sonic-boom#readme",
"keywords": [
"stream",
"fs",
"net",
"fd",
"file",
"descriptor",
"fast"
],
"license": "MIT",
"main": "index.js",
"name": "sonic-boom",
"repository": {
"type": "git",
"url": "git+https://github.com/mcollina/sonic-boom.git"
},
"scripts": {
"test": "standard && tap --no-esm -t 120 test.js"
},
"version": "0.7.7"
}

762
node_modules/sonic-boom/test.js generated vendored Normal file
View file

@ -0,0 +1,762 @@
'use strict'
const { test, tearDown } = require('tap')
const { join } = require('path')
const { fork } = require('child_process')
const fs = require('fs')
const os = require('os')
const path = require('path')
const proxyquire = require('proxyquire')
const SonicBoom = require('.')
const files = []
var count = 0
function file () {
const file = path.join(os.tmpdir(), `sonic-boom-${process.pid}-${process.hrtime().toString()}-${count++}`)
files.push(file)
return file
}
tearDown(() => {
files.forEach((file) => {
try {
fs.unlinkSync(file)
} catch (e) {
console.log(e)
}
})
})
test('sync false', (t) => {
buildTests(t.test, false)
t.end()
})
test('sync true', (t) => {
buildTests(t.test, true)
t.end()
})
function buildTests (test, sync) {
test('write things to a file descriptor', (t) => {
t.plan(6)
const dest = file()
const fd = fs.openSync(dest, 'w')
const stream = new SonicBoom(fd, 0, sync)
stream.on('ready', () => {
t.pass('ready emitted')
})
t.ok(stream.write('hello world\n'))
t.ok(stream.write('something else\n'))
stream.end()
stream.on('finish', () => {
fs.readFile(dest, 'utf8', (err, data) => {
t.error(err)
t.equal(data, 'hello world\nsomething else\n')
})
})
stream.on('close', () => {
t.pass('close emitted')
})
})
test('write things in a streaming fashion', (t) => {
t.plan(8)
const dest = file()
const fd = fs.openSync(dest, 'w')
const stream = new SonicBoom(fd, 0, sync)
t.ok(stream.write('hello world\n'))
stream.once('drain', () => {
fs.readFile(dest, 'utf8', (err, data) => {
t.error(err)
t.equal(data, 'hello world\n')
t.ok(stream.write('something else\n'))
})
stream.once('drain', () => {
fs.readFile(dest, 'utf8', (err, data) => {
t.error(err)
t.equal(data, 'hello world\nsomething else\n')
stream.end()
})
})
})
stream.on('finish', () => {
t.pass('finish emitted')
})
stream.on('close', () => {
t.pass('close emitted')
})
})
test('can be piped into', (t) => {
t.plan(4)
const dest = file()
const fd = fs.openSync(dest, 'w')
const stream = new SonicBoom(fd, 0, sync)
const source = fs.createReadStream(__filename)
source.pipe(stream)
stream.on('finish', () => {
fs.readFile(__filename, 'utf8', (err, expected) => {
t.error(err)
fs.readFile(dest, 'utf8', (err, data) => {
t.error(err)
t.equal(data, expected)
})
})
})
stream.on('close', () => {
t.pass('close emitted')
})
})
test('write things to a file', (t) => {
t.plan(6)
const dest = file()
const stream = new SonicBoom(dest, 0, sync)
stream.on('ready', () => {
t.pass('ready emitted')
})
t.ok(stream.write('hello world\n'))
t.ok(stream.write('something else\n'))
stream.end()
stream.on('finish', () => {
fs.readFile(dest, 'utf8', (err, data) => {
t.error(err)
t.equal(data, 'hello world\nsomething else\n')
})
})
stream.on('close', () => {
t.pass('close emitted')
})
})
test('flushSync', (t) => {
t.plan(4)
const dest = file()
const fd = fs.openSync(dest, 'w')
const stream = new SonicBoom(fd, 4096, sync)
t.ok(stream.write('hello world\n'))
t.ok(stream.write('something else\n'))
stream.flushSync()
// let the file system settle down things
setImmediate(function () {
stream.end()
const data = fs.readFileSync(dest, 'utf8')
t.equal(data, 'hello world\nsomething else\n')
stream.on('close', () => {
t.pass('close emitted')
})
})
})
test('destroy', (t) => {
t.plan(5)
const dest = file()
const fd = fs.openSync(dest, 'w')
const stream = new SonicBoom(fd, 0, sync)
t.ok(stream.write('hello world\n'))
stream.destroy()
t.throws(() => { stream.write('hello world\n') })
fs.readFile(dest, 'utf8', function (err, data) {
t.error(err)
t.equal(data, 'hello world\n')
})
stream.on('finish', () => {
t.fail('finish emitted')
})
stream.on('close', () => {
t.pass('close emitted')
})
})
test('destroy while opening', (t) => {
t.plan(1)
const dest = file()
const stream = new SonicBoom(dest)
stream.destroy()
stream.on('close', () => {
t.pass('close emitted')
})
})
test('minLength', (t) => {
t.plan(8)
const dest = file()
const stream = new SonicBoom(dest, 4096, sync)
stream.on('ready', () => {
t.pass('ready emitted')
})
t.ok(stream.write('hello world\n'))
t.ok(stream.write('something else\n'))
var fail = t.fail
stream.on('drain', fail)
// bad use of timer
// TODO refactor
setTimeout(function () {
fs.readFile(dest, 'utf8', (err, data) => {
t.error(err)
t.equal(data, '')
stream.end()
stream.on('finish', () => {
fs.readFile(dest, 'utf8', (err, data) => {
t.error(err)
t.equal(data, 'hello world\nsomething else\n')
})
})
})
}, 100)
stream.on('close', () => {
t.pass('close emitted')
})
})
test('flush', (t) => {
t.plan(5)
const dest = file()
const fd = fs.openSync(dest, 'w')
const stream = new SonicBoom(fd, 4096, sync)
stream.on('ready', () => {
t.pass('ready emitted')
})
t.ok(stream.write('hello world\n'))
t.ok(stream.write('something else\n'))
stream.flush()
stream.on('drain', () => {
fs.readFile(dest, 'utf8', (err, data) => {
t.error(err)
t.equal(data, 'hello world\nsomething else\n')
stream.end()
})
})
})
test('reopen', (t) => {
t.plan(9)
const dest = file()
const stream = new SonicBoom(dest, 0, sync)
t.ok(stream.write('hello world\n'))
t.ok(stream.write('something else\n'))
const after = dest + '-moved'
stream.once('drain', () => {
t.pass('drain emitted')
fs.renameSync(dest, after)
stream.reopen()
stream.once('ready', () => {
t.pass('ready emitted')
t.ok(stream.write('after reopen\n'))
stream.on('drain', () => {
fs.readFile(after, 'utf8', (err, data) => {
t.error(err)
t.equal(data, 'hello world\nsomething else\n')
fs.readFile(dest, 'utf8', (err, data) => {
t.error(err)
t.equal(data, 'after reopen\n')
stream.end()
})
})
})
})
})
})
test('reopen with buffer', (t) => {
t.plan(9)
const dest = file()
const stream = new SonicBoom(dest, 4096, sync)
t.ok(stream.write('hello world\n'))
t.ok(stream.write('something else\n'))
const after = dest + '-moved'
stream.once('ready', () => {
t.pass('drain emitted')
stream.flush()
fs.renameSync(dest, after)
stream.reopen()
stream.once('ready', () => {
t.pass('ready emitted')
t.ok(stream.write('after reopen\n'))
stream.flush()
stream.on('drain', () => {
fs.readFile(after, 'utf8', (err, data) => {
t.error(err)
t.equal(data, 'hello world\nsomething else\n')
fs.readFile(dest, 'utf8', (err, data) => {
t.error(err)
t.equal(data, 'after reopen\n')
stream.end()
})
})
})
})
})
})
test('reopen if not open', (t) => {
t.plan(3)
const dest = file()
const stream = new SonicBoom(dest, 0, sync)
t.ok(stream.write('hello world\n'))
t.ok(stream.write('something else\n'))
stream.reopen()
stream.end()
stream.on('close', function () {
t.pass('ended')
})
})
test('end after reopen', (t) => {
t.plan(4)
const dest = file()
const stream = new SonicBoom(dest, 4096, sync)
stream.once('ready', () => {
t.pass('ready emitted')
const after = dest + '-moved'
stream.reopen(after)
stream.write('after reopen\n')
stream.on('finish', () => {
t.pass('finish emitted')
fs.readFile(after, 'utf8', (err, data) => {
t.error(err)
t.equal(data, 'after reopen\n')
})
})
stream.end()
})
})
test('end after 2x reopen', (t) => {
t.plan(4)
const dest = file()
const stream = new SonicBoom(dest, 4096, sync)
stream.once('ready', () => {
t.pass('ready emitted')
stream.reopen(dest + '-moved')
const after = dest + '-moved-moved'
stream.reopen(after)
stream.write('after reopen\n')
stream.on('finish', () => {
t.pass('finish emitted')
fs.readFile(after, 'utf8', (err, data) => {
t.error(err)
t.equal(data, 'after reopen\n')
})
})
stream.end()
})
})
test('end if not ready', (t) => {
t.plan(3)
const dest = file()
const stream = new SonicBoom(dest, 4096, sync)
const after = dest + '-moved'
stream.reopen(after)
stream.write('after reopen\n')
stream.on('finish', () => {
t.pass('finish emitted')
fs.readFile(after, 'utf8', (err, data) => {
t.error(err)
t.equal(data, 'after reopen\n')
})
})
stream.end()
})
test('reopen with file', (t) => {
t.plan(9)
const dest = file()
const stream = new SonicBoom(dest, 0, sync)
t.ok(stream.write('hello world\n'))
t.ok(stream.write('something else\n'))
const after = dest + '-new'
stream.once('drain', () => {
t.pass('drain emitted')
stream.reopen(after)
stream.once('ready', () => {
t.pass('ready emitted')
t.ok(stream.write('after reopen\n'))
stream.on('drain', () => {
fs.readFile(dest, 'utf8', (err, data) => {
t.error(err)
t.equal(data, 'hello world\nsomething else\n')
fs.readFile(after, 'utf8', (err, data) => {
t.error(err)
t.equal(data, 'after reopen\n')
stream.end()
})
})
})
})
})
})
test('chunk data accordingly', (t) => {
t.plan(2)
const child = fork(join(__dirname, 'fixtures', 'firehose.js'), { silent: true })
const str = Buffer.alloc(10000).fill('a').toString()
let data = ''
child.stdout.on('data', function (chunk) {
data += chunk.toString()
})
child.stdout.on('end', function () {
t.is(data, str)
})
child.on('close', function (code) {
t.is(code, 0)
})
})
}
test('retry on EAGAIN', (t) => {
t.plan(7)
const fakeFs = Object.create(fs)
fakeFs.write = function (fd, buf, enc, cb) {
t.pass('fake fs.write called')
fakeFs.write = fs.write
const err = new Error('EAGAIN')
err.code = 'EAGAIN'
process.nextTick(cb, err)
}
const SonicBoom = proxyquire('.', {
fs: fakeFs
})
const dest = file()
const fd = fs.openSync(dest, 'w')
const stream = new SonicBoom(fd, 0, false)
stream.on('ready', () => {
t.pass('ready emitted')
})
t.ok(stream.write('hello world\n'))
t.ok(stream.write('something else\n'))
stream.end()
stream.on('finish', () => {
fs.readFile(dest, 'utf8', (err, data) => {
t.error(err)
t.equal(data, 'hello world\nsomething else\n')
})
})
stream.on('close', () => {
t.pass('close emitted')
})
})
test('retry on EAGAIN (sync)', (t) => {
t.plan(7)
const fakeFs = Object.create(fs)
fakeFs.writeSync = function (fd, buf, enc, cb) {
t.pass('fake fs.writeSync called')
fakeFs.writeSync = fs.writeSync
const err = new Error('EAGAIN')
err.code = 'EAGAIN'
throw err
}
const SonicBoom = proxyquire('.', {
fs: fakeFs
})
const dest = file()
const fd = fs.openSync(dest, 'w')
const stream = new SonicBoom(fd, 0, true)
stream.on('ready', () => {
t.pass('ready emitted')
})
t.ok(stream.write('hello world\n'))
t.ok(stream.write('something else\n'))
stream.end()
stream.on('finish', () => {
fs.readFile(dest, 'utf8', (err, data) => {
t.error(err)
t.equal(data, 'hello world\nsomething else\n')
})
})
stream.on('close', () => {
t.pass('close emitted')
})
})
test('write buffers that are not totally written', (t) => {
t.plan(9)
const fakeFs = Object.create(fs)
fakeFs.write = function (fd, buf, enc, cb) {
t.pass('fake fs.write called')
fakeFs.write = function (fd, buf, enc, cb) {
t.pass('calling real fs.write, ' + buf)
fs.write(fd, buf, enc, cb)
}
process.nextTick(cb, null, 0)
}
const SonicBoom = proxyquire('.', {
fs: fakeFs
})
const dest = file()
const fd = fs.openSync(dest, 'w')
const stream = new SonicBoom(fd, 0, false)
stream.on('ready', () => {
t.pass('ready emitted')
})
t.ok(stream.write('hello world\n'))
t.ok(stream.write('something else\n'))
stream.end()
stream.on('finish', () => {
fs.readFile(dest, 'utf8', (err, data) => {
t.error(err)
t.equal(data, 'hello world\nsomething else\n')
})
})
stream.on('close', () => {
t.pass('close emitted')
})
})
test('write buffers that are not totally written with sync mode', (t) => {
t.plan(9)
const fakeFs = Object.create(fs)
fakeFs.writeSync = function (fd, buf, enc) {
t.pass('fake fs.write called')
fakeFs.writeSync = (fd, buf, enc) => {
t.pass('calling real fs.writeSync, ' + buf)
return fs.writeSync(fd, buf, enc)
}
return 0
}
const SonicBoom = proxyquire('.', {
fs: fakeFs
})
const dest = file()
const fd = fs.openSync(dest, 'w')
const stream = new SonicBoom(fd, 0, true)
stream.on('ready', () => {
t.pass('ready emitted')
})
t.ok(stream.write('hello world\n'))
t.ok(stream.write('something else\n'))
stream.end()
stream.on('finish', () => {
fs.readFile(dest, 'utf8', (err, data) => {
t.error(err)
t.equal(data, 'hello world\nsomething else\n')
})
})
stream.on('close', () => {
t.pass('close emitted')
})
})
test('sync writing is fully sync', (t) => {
t.plan(6)
const fakeFs = Object.create(fs)
fakeFs.writeSync = function (fd, buf, enc, cb) {
t.pass('fake fs.write called')
return fs.writeSync(fd, buf, enc)
}
const SonicBoom = proxyquire('.', {
fs: fakeFs
})
const dest = file()
const fd = fs.openSync(dest, 'w')
const stream = new SonicBoom(fd, 0, true)
t.ok(stream.write('hello world\n'))
t.ok(stream.write('something else\n'))
// 'drain' will be only emitted once,
// the number of assertions at the top check this.
stream.on('drain', () => {
t.pass('drain emitted')
})
const data = fs.readFileSync(dest, 'utf8')
t.equal(data, 'hello world\nsomething else\n')
})
// These they will fail on Node 6, as we cannot allocate a string this
// big. It's considered a won't fix on Node 6, as it's deprecated.
if (process.versions.node.indexOf('6.') !== 0) {
test('write enormously large buffers async', (t) => {
t.plan(3)
const dest = file()
const fd = fs.openSync(dest, 'w')
const stream = new SonicBoom(fd, 0, false)
const buf = Buffer.alloc(1024).fill('x').toString() // 1 MB
let length = 0
for (let i = 0; i < 1024 * 1024; i++) {
length += buf.length
stream.write(buf)
}
stream.end()
stream.on('finish', () => {
fs.stat(dest, (err, stat) => {
t.error(err)
t.equal(stat.size, length)
})
})
stream.on('close', () => {
t.pass('close emitted')
})
})
test('write enormously large buffers sync', (t) => {
t.plan(3)
const dest = file()
const fd = fs.openSync(dest, 'w')
const stream = new SonicBoom(fd, 0, true)
const buf = Buffer.alloc(1024).fill('x').toString() // 1 MB
let length = 0
for (let i = 0; i < 1024 * 1024; i++) {
length += buf.length
stream.write(buf)
}
stream.end()
stream.on('finish', () => {
fs.stat(dest, (err, stat) => {
t.error(err)
t.equal(stat.size, length)
})
})
stream.on('close', () => {
t.pass('close emitted')
})
})
}
test('write enormously large buffers sync with utf8 multi-byte split', (t) => {
t.plan(4)
const dest = file()
const fd = fs.openSync(dest, 'w')
const stream = new SonicBoom(fd, 0, true)
let buf = Buffer.alloc((1024 * 16) - 2).fill('x') // 16MB - 3B
const length = buf.length + 4
buf = buf.toString() + '🌲' // 16 MB + 1B
stream.write(buf)
stream.end()
stream.on('finish', () => {
fs.stat(dest, (err, stat) => {
t.error(err)
t.equal(stat.size, length)
const char = Buffer.alloc(4)
const fd = fs.openSync(dest, 'r')
fs.readSync(fd, char, 0, 4, length - 4)
t.equal(char.toString(), '🌲')
})
})
stream.on('close', () => {
t.pass('close emitted')
})
})