thread-stream 0.12.0 → 0.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.js CHANGED
@@ -12,6 +12,8 @@ const {
12
12
  const buffer = require('buffer')
13
13
  const assert = require('assert')
14
14
 
15
+ const kImpl = Symbol('kImpl')
16
+
15
17
  // V8 limit for string size
16
18
  const MAX_STRING = buffer.constants.MAX_STRING_LENGTH
17
19
 
@@ -50,8 +52,8 @@ function createWorker (stream, opts) {
50
52
  filename: filename.indexOf('file://') === 0
51
53
  ? filename
52
54
  : pathToFileURL(filename).href,
53
- dataBuf: stream._dataBuf,
54
- stateBuf: stream._stateBuf,
55
+ dataBuf: stream[kImpl].dataBuf,
56
+ stateBuf: stream[kImpl].stateBuf,
55
57
  workerData
56
58
  }
57
59
  })
@@ -68,62 +70,62 @@ function createWorker (stream, opts) {
68
70
  }
69
71
 
70
72
  function drain (stream) {
71
- assert(!stream._sync)
72
- if (stream.needDrain) {
73
- stream.needDrain = false
73
+ assert(!stream[kImpl].sync)
74
+ if (stream[kImpl].needDrain) {
75
+ stream[kImpl].needDrain = false
74
76
  stream.emit('drain')
75
77
  }
76
78
  }
77
79
 
78
80
  function nextFlush (stream) {
79
- const writeIndex = Atomics.load(stream._state, WRITE_INDEX)
80
- let leftover = stream._data.length - writeIndex
81
+ const writeIndex = Atomics.load(stream[kImpl].state, WRITE_INDEX)
82
+ let leftover = stream[kImpl].data.length - writeIndex
81
83
 
82
84
  if (leftover > 0) {
83
- if (stream.buf.length === 0) {
84
- stream.flushing = false
85
+ if (stream[kImpl].buf.length === 0) {
86
+ stream[kImpl].flushing = false
85
87
 
86
- if (stream.ending) {
87
- stream._end()
88
- } else if (stream.needDrain) {
88
+ if (stream[kImpl].ending) {
89
+ end(stream)
90
+ } else if (stream[kImpl].needDrain) {
89
91
  process.nextTick(drain, stream)
90
92
  }
91
93
 
92
94
  return
93
95
  }
94
96
 
95
- let toWrite = stream.buf.slice(0, leftover)
97
+ let toWrite = stream[kImpl].buf.slice(0, leftover)
96
98
  let toWriteBytes = Buffer.byteLength(toWrite)
97
99
  if (toWriteBytes <= leftover) {
98
- stream.buf = stream.buf.slice(leftover)
100
+ stream[kImpl].buf = stream[kImpl].buf.slice(leftover)
99
101
  // process._rawDebug('writing ' + toWrite.length)
100
- stream._write(toWrite, nextFlush.bind(null, stream))
102
+ write(stream, toWrite, nextFlush.bind(null, stream))
101
103
  } else {
102
104
  // multi-byte utf-8
103
105
  stream.flush(() => {
104
- Atomics.store(stream._state, READ_INDEX, 0)
105
- Atomics.store(stream._state, WRITE_INDEX, 0)
106
+ Atomics.store(stream[kImpl].state, READ_INDEX, 0)
107
+ Atomics.store(stream[kImpl].state, WRITE_INDEX, 0)
106
108
 
107
109
  // Find a toWrite length that fits the buffer
108
110
  // it must exists as the buffer is at least 4 bytes length
109
111
  // and the max utf-8 length for a char is 4 bytes.
110
- while (toWriteBytes > stream.buf.length) {
112
+ while (toWriteBytes > stream[kImpl].buf.length) {
111
113
  leftover = leftover / 2
112
- toWrite = stream.buf.slice(0, leftover)
114
+ toWrite = stream[kImpl].buf.slice(0, leftover)
113
115
  toWriteBytes = Buffer.byteLength(toWrite)
114
116
  }
115
- stream.buf = stream.buf.slice(leftover)
116
- stream._write(toWrite, nextFlush.bind(null, stream))
117
+ stream[kImpl].buf = stream[kImpl].buf.slice(leftover)
118
+ write(stream, toWrite, nextFlush.bind(null, stream))
117
119
  })
118
120
  }
119
121
  } else if (leftover === 0) {
120
- if (writeIndex === 0 && stream.buf.length === 0) {
122
+ if (writeIndex === 0 && stream[kImpl].buf.length === 0) {
121
123
  // we had a flushSync in the meanwhile
122
124
  return
123
125
  }
124
126
  stream.flush(() => {
125
- Atomics.store(stream._state, READ_INDEX, 0)
126
- Atomics.store(stream._state, WRITE_INDEX, 0)
127
+ Atomics.store(stream[kImpl].state, READ_INDEX, 0)
128
+ Atomics.store(stream[kImpl].state, WRITE_INDEX, 0)
127
129
  nextFlush(stream)
128
130
  })
129
131
  } else {
@@ -148,12 +150,12 @@ function onWorkerMessage (msg) {
148
150
  this.stream = new WeakRef(stream)
149
151
 
150
152
  stream.flush(() => {
151
- this.ready = true
153
+ stream[kImpl].ready = true
152
154
  stream.emit('ready')
153
155
  })
154
156
  break
155
157
  case 'ERROR':
156
- stream._destroy(msg.err)
158
+ destroy(stream, msg.err)
157
159
  break
158
160
  default:
159
161
  throw new Error('this should not happen: ' + msg.code)
@@ -169,7 +171,7 @@ function onWorkerExit (code) {
169
171
  registry.unregister(stream)
170
172
  stream.worker.exited = true
171
173
  stream.worker.off('exit', onWorkerExit)
172
- stream._destroy(code !== 0 ? new Error('The worker thread exited') : null)
174
+ destroy(stream, code !== 0 ? new Error('The worker thread exited') : null)
173
175
  }
174
176
 
175
177
  class ThreadStream extends EventEmitter {
@@ -180,157 +182,87 @@ class ThreadStream extends EventEmitter {
180
182
  throw new Error('bufferSize must at least fit a 4-byte utf-8 char')
181
183
  }
182
184
 
183
- this._stateBuf = new SharedArrayBuffer(128)
184
- this._state = new Int32Array(this._stateBuf)
185
- this._dataBuf = new SharedArrayBuffer(opts.bufferSize || 4 * 1024 * 1024)
186
- this._data = Buffer.from(this._dataBuf)
187
- this._sync = opts.sync || false
188
- this.worker = createWorker(this, opts)
189
- this.ending = false
190
- this.ended = false
191
- this.needDrain = false
192
- this.destroyed = false
193
- this.flushing = false
194
- this.ready = false
195
-
196
- this.buf = ''
197
- }
198
-
199
- _destroy (err) {
200
- if (this.destroyed) {
201
- return
202
- }
203
- this.destroyed = true
204
-
205
- if (err) {
206
- this.emit('error', err)
207
- }
208
-
209
- if (!this.worker.exited) {
210
- this.worker.terminate()
211
- .catch(() => {})
212
- .then(() => {
213
- this.emit('close')
214
- })
215
- } else {
216
- setImmediate(() => {
217
- this.emit('close')
218
- })
219
- }
220
- }
221
-
222
- _write (data, cb) {
223
- // data is smaller than the shared buffer length
224
- const current = Atomics.load(this._state, WRITE_INDEX)
225
- const length = Buffer.byteLength(data)
226
- this._data.write(data, current)
227
- Atomics.store(this._state, WRITE_INDEX, current + length)
228
- Atomics.notify(this._state, WRITE_INDEX)
229
- cb()
230
- return true
185
+ this[kImpl] = {}
186
+ this[kImpl].stateBuf = new SharedArrayBuffer(128)
187
+ this[kImpl].state = new Int32Array(this[kImpl].stateBuf)
188
+ this[kImpl].dataBuf = new SharedArrayBuffer(opts.bufferSize || 4 * 1024 * 1024)
189
+ this[kImpl].data = Buffer.from(this[kImpl].dataBuf)
190
+ this[kImpl].sync = opts.sync || false
191
+ this[kImpl].ending = false
192
+ this[kImpl].ended = false
193
+ this[kImpl].needDrain = false
194
+ this[kImpl].destroyed = false
195
+ this[kImpl].flushing = false
196
+ this[kImpl].ready = false
197
+ this[kImpl].finished = false
198
+ this[kImpl].errored = null
199
+ this[kImpl].closed = false
200
+ this[kImpl].buf = ''
201
+
202
+ // TODO (fix): Make private?
203
+ this.worker = createWorker(this, opts) // TODO (fix): make private
231
204
  }
232
205
 
233
206
  write (data) {
234
- if (this.destroyed) {
207
+ if (this[kImpl].destroyed) {
235
208
  throw new Error('the worker has exited')
236
209
  }
237
210
 
238
- if (this.ending) {
211
+ if (this[kImpl].ending) {
239
212
  throw new Error('the worker is ending')
240
213
  }
241
214
 
242
- if (this.flushing && this.buf.length + data.length >= MAX_STRING) {
215
+ if (this[kImpl].flushing && this[kImpl].buf.length + data.length >= MAX_STRING) {
243
216
  try {
244
- this._writeSync()
245
- this.flushing = true
217
+ writeSync(this)
218
+ this[kImpl].flushing = true
246
219
  } catch (err) {
247
- this._destroy(err)
220
+ destroy(this, err)
248
221
  return false
249
222
  }
250
223
  }
251
224
 
252
- this.buf += data
225
+ this[kImpl].buf += data
253
226
 
254
- if (this._sync) {
227
+ if (this[kImpl].sync) {
255
228
  try {
256
- this._writeSync()
229
+ writeSync(this)
257
230
  return true
258
231
  } catch (err) {
259
- this._destroy(err)
232
+ destroy(this, err)
260
233
  return false
261
234
  }
262
235
  }
263
236
 
264
- if (!this.flushing) {
265
- this.flushing = true
237
+ if (!this[kImpl].flushing) {
238
+ this[kImpl].flushing = true
266
239
  setImmediate(nextFlush, this)
267
240
  }
268
241
 
269
- this.needDrain = this._data.length - this.buf.length - Atomics.load(this._state, WRITE_INDEX) <= 0
270
- return !this.needDrain
242
+ this[kImpl].needDrain = this[kImpl].data.length - this[kImpl].buf.length - Atomics.load(this[kImpl].state, WRITE_INDEX) <= 0
243
+ return !this[kImpl].needDrain
271
244
  }
272
245
 
273
246
  end () {
274
- if (this.destroyed) {
247
+ if (this[kImpl].destroyed) {
275
248
  throw new Error('the worker has exited')
276
249
  }
277
250
 
278
- this.ending = true
279
- this._end()
280
- }
281
-
282
- _end () {
283
- if (this.ended || !this.ending || this.flushing) {
284
- return
285
- }
286
- this.ended = true
287
-
288
- try {
289
- this.flushSync()
290
-
291
- let readIndex = Atomics.load(this._state, READ_INDEX)
292
-
293
- // process._rawDebug('writing index')
294
- Atomics.store(this._state, WRITE_INDEX, -1)
295
- // process._rawDebug(`(end) readIndex (${Atomics.load(this._state, READ_INDEX)}) writeIndex (${Atomics.load(this._state, WRITE_INDEX)})`)
296
- Atomics.notify(this._state, WRITE_INDEX)
297
-
298
- // Wait for the process to complete
299
- let spins = 0
300
- while (readIndex !== -1) {
301
- // process._rawDebug(`read = ${read}`)
302
- Atomics.wait(this._state, READ_INDEX, readIndex, 1000)
303
- readIndex = Atomics.load(this._state, READ_INDEX)
304
-
305
- if (readIndex === -2) {
306
- throw new Error('end() failed')
307
- }
308
-
309
- if (++spins === 10) {
310
- throw new Error('end() took too long (10s)')
311
- }
312
- }
313
-
314
- process.nextTick(() => {
315
- this.emit('finish')
316
- })
317
- } catch (err) {
318
- this._destroy(err)
319
- }
320
- // process._rawDebug('end finished...')
251
+ this[kImpl].ending = true
252
+ end(this)
321
253
  }
322
254
 
323
255
  flush (cb) {
324
- if (this.destroyed) {
256
+ if (this[kImpl].destroyed) {
325
257
  throw new Error('the worker has exited')
326
258
  }
327
259
 
328
260
  // TODO write all .buf
329
- const writeIndex = Atomics.load(this._state, WRITE_INDEX)
330
- // process._rawDebug(`(flush) readIndex (${Atomics.load(this._state, READ_INDEX)}) writeIndex (${Atomics.load(this._state, WRITE_INDEX)})`)
331
- wait(this._state, READ_INDEX, writeIndex, Infinity, (err, res) => {
261
+ const writeIndex = Atomics.load(this[kImpl].state, WRITE_INDEX)
262
+ // process._rawDebug(`(flush) readIndex (${Atomics.load(this.state, READ_INDEX)}) writeIndex (${Atomics.load(this.state, WRITE_INDEX)})`)
263
+ wait(this[kImpl].state, READ_INDEX, writeIndex, Infinity, (err, res) => {
332
264
  if (err) {
333
- this._destroy(err)
265
+ destroy(this, err)
334
266
  process.nextTick(cb, err)
335
267
  return
336
268
  }
@@ -343,109 +275,220 @@ class ThreadStream extends EventEmitter {
343
275
  })
344
276
  }
345
277
 
346
- _writeSync () {
347
- const cb = () => {
348
- if (this.ending) {
349
- this._end()
350
- } else if (this.needDrain) {
351
- process.nextTick(drain, this)
352
- }
278
+ flushSync () {
279
+ if (this[kImpl].destroyed) {
280
+ throw new Error('the worker has exited')
353
281
  }
354
- this.flushing = false
355
-
356
- while (this.buf.length !== 0) {
357
- const writeIndex = Atomics.load(this._state, WRITE_INDEX)
358
- let leftover = this._data.length - writeIndex
359
- if (leftover === 0) {
360
- this._flushSync()
361
- Atomics.store(this._state, READ_INDEX, 0)
362
- Atomics.store(this._state, WRITE_INDEX, 0)
363
- continue
364
- } else if (leftover < 0) {
365
- // This should never happen
366
- throw new Error('overwritten')
367
- }
368
282
 
369
- let toWrite = this.buf.slice(0, leftover)
370
- let toWriteBytes = Buffer.byteLength(toWrite)
371
- if (toWriteBytes <= leftover) {
372
- this.buf = this.buf.slice(leftover)
373
- // process._rawDebug('writing ' + toWrite.length)
374
- this._write(toWrite, cb)
375
- } else {
376
- // multi-byte utf-8
377
- this._flushSync()
378
- Atomics.store(this._state, READ_INDEX, 0)
379
- Atomics.store(this._state, WRITE_INDEX, 0)
283
+ writeSync(this)
284
+ flushSync(this)
285
+ }
380
286
 
381
- // Find a toWrite length that fits the buffer
382
- // it must exists as the buffer is at least 4 bytes length
383
- // and the max utf-8 length for a char is 4 bytes.
384
- while (toWriteBytes > this.buf.length) {
385
- leftover = leftover / 2
386
- toWrite = this.buf.slice(0, leftover)
387
- toWriteBytes = Buffer.byteLength(toWrite)
388
- }
389
- this.buf = this.buf.slice(leftover)
390
- this._write(toWrite, cb)
391
- }
392
- }
287
+ unref () {
288
+ this.worker.unref()
393
289
  }
394
290
 
395
- flushSync () {
396
- if (this.destroyed) {
397
- throw new Error('the worker has exited')
398
- }
291
+ ref () {
292
+ this.worker.ref()
293
+ }
399
294
 
400
- this._writeSync()
401
- this._flushSync()
295
+ get ready () {
296
+ return this[kImpl].ready
402
297
  }
403
298
 
404
- _flushSync () {
405
- if (this.flushing) {
406
- throw new Error('unable to flush while flushing')
407
- }
299
+ get destroyed () {
300
+ return this[kImpl].destroyed
301
+ }
408
302
 
409
- // process._rawDebug('flushSync started')
303
+ get closed () {
304
+ return this[kImpl].closed
305
+ }
410
306
 
411
- const writeIndex = Atomics.load(this._state, WRITE_INDEX)
307
+ get writable () {
308
+ return !this[kImpl].destroyed && !this[kImpl].ending
309
+ }
412
310
 
413
- let spins = 0
311
+ get writableEnded () {
312
+ return this[kImpl].ending
313
+ }
414
314
 
415
- // TODO handle deadlock
416
- while (true) {
417
- const readIndex = Atomics.load(this._state, READ_INDEX)
315
+ get writableFinished () {
316
+ return this[kImpl].finished
317
+ }
418
318
 
419
- if (readIndex === -2) {
420
- throw new Error('_flushSync failed')
421
- }
319
+ get writableNeedDrain () {
320
+ return this[kImpl].needDrain
321
+ }
322
+
323
+ get writableObjectMode () {
324
+ return false
325
+ }
326
+
327
+ get writableErrored () {
328
+ return this[kImpl].errored
329
+ }
330
+ }
331
+
332
+ function destroy (stream, err) {
333
+ if (stream[kImpl].destroyed) {
334
+ return
335
+ }
336
+ stream[kImpl].destroyed = true
337
+
338
+ if (err) {
339
+ stream[kImpl].errored = err
340
+ stream.emit('error', err)
341
+ }
342
+
343
+ if (!stream.worker.exited) {
344
+ stream.worker.terminate()
345
+ .catch(() => {})
346
+ .then(() => {
347
+ stream[kImpl].closed = true
348
+ stream.emit('close')
349
+ })
350
+ } else {
351
+ setImmediate(() => {
352
+ stream[kImpl].closed = true
353
+ stream.emit('close')
354
+ })
355
+ }
356
+ }
357
+
358
+ function write (stream, data, cb) {
359
+ // data is smaller than the shared buffer length
360
+ const current = Atomics.load(stream[kImpl].state, WRITE_INDEX)
361
+ const length = Buffer.byteLength(data)
362
+ stream[kImpl].data.write(data, current)
363
+ Atomics.store(stream[kImpl].state, WRITE_INDEX, current + length)
364
+ Atomics.notify(stream[kImpl].state, WRITE_INDEX)
365
+ cb()
366
+ return true
367
+ }
368
+
369
+ function end (stream) {
370
+ if (stream[kImpl].ended || !stream[kImpl].ending || stream[kImpl].flushing) {
371
+ return
372
+ }
373
+ stream[kImpl].ended = true
422
374
 
423
- // process._rawDebug(`(flushSync) readIndex (${readIndex}) writeIndex (${writeIndex})`)
424
- if (readIndex !== writeIndex) {
425
- // TODO this timeouts for some reason.
426
- Atomics.wait(this._state, READ_INDEX, readIndex, 1000)
427
- } else {
428
- break
375
+ try {
376
+ stream.flushSync()
377
+
378
+ let readIndex = Atomics.load(stream[kImpl].state, READ_INDEX)
379
+
380
+ // process._rawDebug('writing index')
381
+ Atomics.store(stream[kImpl].state, WRITE_INDEX, -1)
382
+ // process._rawDebug(`(end) readIndex (${Atomics.load(stream.state, READ_INDEX)}) writeIndex (${Atomics.load(stream.state, WRITE_INDEX)})`)
383
+ Atomics.notify(stream[kImpl].state, WRITE_INDEX)
384
+
385
+ // Wait for the process to complete
386
+ let spins = 0
387
+ while (readIndex !== -1) {
388
+ // process._rawDebug(`read = ${read}`)
389
+ Atomics.wait(stream[kImpl].state, READ_INDEX, readIndex, 1000)
390
+ readIndex = Atomics.load(stream[kImpl].state, READ_INDEX)
391
+
392
+ if (readIndex === -2) {
393
+ throw new Error('end() failed')
429
394
  }
430
395
 
431
396
  if (++spins === 10) {
432
- throw new Error('_flushSync took too long (10s)')
397
+ throw new Error('end() took too long (10s)')
433
398
  }
434
399
  }
435
- // process._rawDebug('flushSync finished')
400
+
401
+ process.nextTick(() => {
402
+ stream[kImpl].finished = true
403
+ stream.emit('finish')
404
+ })
405
+ } catch (err) {
406
+ destroy(stream, err)
407
+ }
408
+ // process._rawDebug('end finished...')
409
+ }
410
+
411
+ function writeSync (stream) {
412
+ const cb = () => {
413
+ if (stream[kImpl].ending) {
414
+ end(stream)
415
+ } else if (stream[kImpl].needDrain) {
416
+ process.nextTick(drain, stream)
417
+ }
436
418
  }
419
+ stream[kImpl].flushing = false
420
+
421
+ while (stream[kImpl].buf.length !== 0) {
422
+ const writeIndex = Atomics.load(stream[kImpl].state, WRITE_INDEX)
423
+ let leftover = stream[kImpl].data.length - writeIndex
424
+ if (leftover === 0) {
425
+ flushSync(stream)
426
+ Atomics.store(stream[kImpl].state, READ_INDEX, 0)
427
+ Atomics.store(stream[kImpl].state, WRITE_INDEX, 0)
428
+ continue
429
+ } else if (leftover < 0) {
430
+ // stream should never happen
431
+ throw new Error('overwritten')
432
+ }
437
433
 
438
- unref () {
439
- this.worker.unref()
434
+ let toWrite = stream[kImpl].buf.slice(0, leftover)
435
+ let toWriteBytes = Buffer.byteLength(toWrite)
436
+ if (toWriteBytes <= leftover) {
437
+ stream[kImpl].buf = stream[kImpl].buf.slice(leftover)
438
+ // process._rawDebug('writing ' + toWrite.length)
439
+ write(stream, toWrite, cb)
440
+ } else {
441
+ // multi-byte utf-8
442
+ flushSync(stream)
443
+ Atomics.store(stream[kImpl].state, READ_INDEX, 0)
444
+ Atomics.store(stream[kImpl].state, WRITE_INDEX, 0)
445
+
446
+ // Find a toWrite length that fits the buffer
447
+ // it must exists as the buffer is at least 4 bytes length
448
+ // and the max utf-8 length for a char is 4 bytes.
449
+ while (toWriteBytes > stream[kImpl].buf.length) {
450
+ leftover = leftover / 2
451
+ toWrite = stream[kImpl].buf.slice(0, leftover)
452
+ toWriteBytes = Buffer.byteLength(toWrite)
453
+ }
454
+ stream[kImpl].buf = stream[kImpl].buf.slice(leftover)
455
+ write(stream, toWrite, cb)
456
+ }
440
457
  }
458
+ }
441
459
 
442
- ref () {
443
- this.worker.ref()
460
+ function flushSync (stream) {
461
+ if (stream[kImpl].flushing) {
462
+ throw new Error('unable to flush while flushing')
444
463
  }
445
464
 
446
- get writable () {
447
- return !this.destroyed && !this.ending
465
+ // process._rawDebug('flushSync started')
466
+
467
+ const writeIndex = Atomics.load(stream[kImpl].state, WRITE_INDEX)
468
+
469
+ let spins = 0
470
+
471
+ // TODO handle deadlock
472
+ while (true) {
473
+ const readIndex = Atomics.load(stream[kImpl].state, READ_INDEX)
474
+
475
+ if (readIndex === -2) {
476
+ throw new Error('_flushSync failed')
477
+ }
478
+
479
+ // process._rawDebug(`(flushSync) readIndex (${readIndex}) writeIndex (${writeIndex})`)
480
+ if (readIndex !== writeIndex) {
481
+ // TODO stream timeouts for some reason.
482
+ Atomics.wait(stream[kImpl].state, READ_INDEX, readIndex, 1000)
483
+ } else {
484
+ break
485
+ }
486
+
487
+ if (++spins === 10) {
488
+ throw new Error('_flushSync took too long (10s)')
489
+ }
448
490
  }
491
+ // process._rawDebug('flushSync finished')
449
492
  }
450
493
 
451
494
  module.exports = ThreadStream
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "thread-stream",
3
- "version": "0.12.0",
3
+ "version": "0.12.1",
4
4
  "description": "A streaming way to send data to a Node.js Worker Thread",
5
5
  "main": "index.js",
6
6
  "devDependencies": {
package/test/base.test.js CHANGED
@@ -9,7 +9,7 @@ const { MessageChannel } = require('worker_threads')
9
9
  const { once } = require('events')
10
10
 
11
11
  test('base sync=true', function (t) {
12
- t.plan(7)
12
+ t.plan(15)
13
13
 
14
14
  const dest = file()
15
15
  const stream = new ThreadStream({
@@ -18,23 +18,32 @@ test('base sync=true', function (t) {
18
18
  sync: true
19
19
  })
20
20
 
21
+ t.same(stream.writableObjectMode, false)
22
+
23
+ t.same(stream.writableFinished, false)
21
24
  stream.on('finish', () => {
25
+ t.same(stream.writableFinished, true)
22
26
  readFile(dest, 'utf8', (err, data) => {
23
27
  t.error(err)
24
28
  t.equal(data, 'hello world\nsomething else\n')
25
29
  })
26
30
  })
27
31
 
32
+ t.same(stream.closed, false)
28
33
  stream.on('close', () => {
34
+ t.same(stream.closed, true)
29
35
  t.notOk(stream.writable)
30
36
  t.pass('close emitted')
31
37
  })
32
38
 
39
+ t.same(stream.writableNeedDrain, false)
33
40
  t.ok(stream.write('hello world\n'))
34
41
  t.ok(stream.write('something else\n'))
35
42
  t.ok(stream.writable)
36
43
 
44
+ t.same(stream.writableEnded, false)
37
45
  stream.end()
46
+ t.same(stream.writableEnded, true)
38
47
  })
39
48
 
40
49
  test('overflow sync=true', function (t) {
@@ -87,6 +96,8 @@ test('overflow sync=false', function (t) {
87
96
 
88
97
  let count = 0
89
98
 
99
+ t.same(stream.writableNeedDrain, false)
100
+
90
101
  // Write 10 chars, 20 times
91
102
  function write () {
92
103
  if (count++ === 20) {
@@ -95,7 +106,9 @@ test('overflow sync=false', function (t) {
95
106
  return
96
107
  }
97
108
 
98
- stream.write('aaaaaaaaaa')
109
+ if (!stream.write('aaaaaaaaaa')) {
110
+ t.same(stream.writableNeedDrain, true)
111
+ }
99
112
  // do not wait for drain event
100
113
  setImmediate(write)
101
114
  }
@@ -103,6 +116,7 @@ test('overflow sync=false', function (t) {
103
116
  write()
104
117
 
105
118
  stream.on('drain', () => {
119
+ t.same(stream.writableNeedDrain, false)
106
120
  t.pass('drain')
107
121
  })
108
122
 
@@ -6,7 +6,7 @@ const ThreadStream = require('..')
6
6
  const isYarnPnp = process.versions.pnp !== undefined
7
7
 
8
8
  test('yarn module resolution', { skip: !isYarnPnp }, t => {
9
- t.plan(4)
9
+ t.plan(6)
10
10
 
11
11
  const modulePath = require.resolve('pino-elasticsearch')
12
12
  t.match(modulePath, /.*\.zip.*/)
@@ -17,7 +17,9 @@ test('yarn module resolution', { skip: !isYarnPnp }, t => {
17
17
  sync: true
18
18
  })
19
19
 
20
- stream.on('error', () => {
20
+ t.same(stream.writableErrored, null)
21
+ stream.on('error', (err) => {
22
+ t.same(stream.writableErrored, err)
21
23
  t.pass('error emitted')
22
24
  })
23
25